WCF Restful CORS无法执行POST

时间:2015-10-11 16:48:14

标签: jquery ajax wcf rest cors

我阅读如何在WCF中创建Restful 教程并从WCFTutorial下载示例代码。 有1个主机(名称:MYFirstRestfulServiceHost)和1个客户端(名称:WebClient)。 WebClient和MYFirstRestfulServiceHost位于不同的域中。 因此,当我发出GET / POST请求时,我遇到了一个问题:状态405"方法不允许"。

经过2天的研究,我发现我必须在Host app.config中添加一些配置,以便在跨域wcf服务上执行GET / POST请求。

在app.config中添加配置后,我成功在WebClient中执行GET请求,但是无法通过按WebClient中的按钮执行剩余的POST,DELETE和PUT。

请建议我应该配置什么以使其成功。

以下是源代码和配置:

IEmployeeService.cs

namespace MyFirstRESTfulService
{
    [ServiceContract()]
    public interface IEmployeeService
    {
        [WebGet(UriTemplate = "Employee", ResponseFormat = WebMessageFormat.Json)]
        [OperationContract]
        List<Employee> GetAllEmployeeDetails();

        [WebGet(UriTemplate = "Employee?id={id}", ResponseFormat = WebMessageFormat.Json)]
        [OperationContract]
        Employee GetEmployee(int Id);

        [WebInvoke(Method = "POST", UriTemplate = "EmployeePOST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        [OperationContract]
        void AddEmployee(Employee newEmp);

        [WebInvoke(Method = "PUT", UriTemplate = "EmployeePUT", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        [OperationContract]
        void UpdateEmployee(Employee newEmp);

        [WebInvoke(Method = "DELETE", UriTemplate = "Employee/{empId}", ResponseFormat = WebMessageFormat.Json)]
        [OperationContract]
        void DeleteEmployee(string empId);
    }
}

EmployeeService.cs

namespace MyFirstRESTfulService
{
    [ServiceContract()]
    public interface IEmployeeService
    {
        [WebGet(UriTemplate = "Employee", ResponseFormat = WebMessageFormat.Json)]
        [OperationContract]
        List<Employee> GetAllEmployeeDetails();

        [WebGet(UriTemplate = "Employee?id={id}", ResponseFormat = WebMessageFormat.Json)]
        [OperationContract]
        Employee GetEmployee(int Id);

        [WebInvoke(Method = "POST", UriTemplate = "EmployeePOST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        [OperationContract]
        void AddEmployee(Employee newEmp);

        [WebInvoke(Method = "PUT", UriTemplate = "EmployeePUT", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        [OperationContract]
        void UpdateEmployee(Employee newEmp);

        [WebInvoke(Method = "DELETE", UriTemplate = "Employee/{empId}", ResponseFormat = WebMessageFormat.Json)]
        [OperationContract]
        void DeleteEmployee(string empId);
    }
}

MyFirstRestfulServiceHost

的app.config

<?xml version="1.0"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="Content-Type" />
        <add name="Access-Control-Allow-Methods" value="POST,GET,OPTIONS" />
        <add name="Access-Control-Max-Age" value="1728000" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
    <standardEndpoints>
      <webHttpEndpoint>
        <standardEndpoint crossDomainScriptAccessEnabled="true"></standardEndpoint>
      </webHttpEndpoint>
      <webScriptEndpoint>
        <standardEndpoint crossDomainScriptAccessEnabled="true"></standardEndpoint>
      </webScriptEndpoint>
    </standardEndpoints>
    <bindings>
      <webHttpBinding>
        <binding name="webHttpBindingWithJsonP" crossDomainScriptAccessEnabled="true"/>
      </webHttpBinding>
    </bindings>
  </system.serviceModel>

</configuration>

MyFirstRESTfulServiceHost

Program.cs的

static void Main(string[] args)
{
    try
    {

        Uri httpUrl = new Uri("http://localhost:8090/MyService/EmployeeService");
        WebServiceHost host = new WebServiceHost(typeof(MyFirstRESTfulService.EmployeeService), httpUrl);
        host.Open();

        foreach (ServiceEndpoint se in host.Description.Endpoints)
                Console.WriteLine("Service is host with endpoint " + se.Address);
        Console.WriteLine("Host is running... Press <Enter> key to stop");
        Console.ReadLine();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        Console.ReadLine();
    }
}

WebClient

Default.aspx的

 <script type="text/javascript" >
      function RefreshPage() {
          var serviceUrl = "http://localhost:8090/MyService/EmployeeService/Employee";
          $.ajax({
              type: "GET",
              url: serviceUrl,
              dataType: 'jsonp',
              contentType: "application/json; charset=utf-8",
              success: function (data) {
                  var itemRow = "<table>";
                  $.each(data, function (index, item) {
                      itemRow += "<tr><td>" + item.EmpId + "</td><td>" + item.Fname + "</td></tr>";
                  });
                  itemRow += "</table>";

                  $("#divItems").html(itemRow);

              },
              error: ServiceFailed
          });
      }

      function POSTMethodCall() {
           var EmpUser = [{ "EmpId": "13", "Fname": "WebClientUser", "Lname": "Raju", "JoinDate": Date(1224043200000), "Age": "23", "Salary": "12000", "Designation": "Software Engineer"}];
           var st = JSON.stringify(EmpUser);
          $.ajax({
              type: "POST",
              url: "http://localhost:8090/MyService/EmployeeService/EmployeePOST",
              data: JSON.stringify(EmpUser),
               contentType: "application/json; charset=utf-8",
              dataType: "jsonp",
              success: function (data) {
                  // Play with response returned in JSON format
              },
              error:ServiceFailed
          });

      }
      function DELETEMethodCall() {
          $.ajax({
              type: "DELETE",
              url: "http://localhost:8090/MyService/EmployeeService/Employee/2",
              data: "{}",
              contentType: "application/json; charset=utf-8",
              dataType: "jsonp",
              success: function (data) {
                  // Play with response returned in JSON format
              },
              error: function (msg) {
                  alert(msg);
              }
          });

      }

      function PUTMethodCall() {
          var EmpUser = [{ "EmpId": "3", "Fname": "WebClientUser", "Lname": "Raju", "JoinDate": Date(1224043200000), "Age": "23", "Salary": "12000", "Designation": "Software Engineer"}];
          $.ajax({
              type: "PUT",
              url: "http://localhost:8090/MyService/EmployeeService/EmployeePUT",
              data: EmpUser,
              contentType: "application/json; charset=utf-8",
              dataType: "jsonp",
              success: function (data) {
                  alert('success');
                  // Play with response returned in JSON format
              },

               error: ServiceFailed
          });

      }
      function ServiceFailed(xhr) {
           alert("response:" + xhr.responseText);

          if (xhr.responseText) {
              var err = xhr.responseText;
              if (err)
                  error(err);
              else
                  error({ Message: "Unknown server error." })
          }

          return;
      }
  </script>
<input type="button" onclick="PUTMethodCall();" name="btnUpdate"  value ="Update" />
<input type="button" onclick="DELETEMethodCall();" name="btnDelete"  value ="Delete" />
<input type="button" onclick="POSTMethodCall();" name="btnAdd"  value ="Add" />
<input type="button" onclick="RefreshPage()" name="btnRefesh"  value ="Refresh" />
    <div id="divItems"></div>

enter image description here

通过按“刷新”按钮(GET)检索员工信息列表成功。但是,更新,删除和添加失败。 从chrome中按“添加”按钮后,图像显示状态405错误。 enter image description here

我非常感谢您的建议和帮助!

2 个答案:

答案 0 :(得分:2)

我不相信这里的问题是由CORS引起的,但事实上它实际上是一个GET请求,而不是所需的POST。

$.ajax({
  type: "POST",
  url: "http://localhost:8090/MyService/EmployeeService/EmployeePOST",
  data: JSON.stringify(EmpUser),
  contentType: "application/json; charset=utf-8",

  dataType: "jsonp",
  ^^^^^^^^^

  success: function (data) {
    // Play with response returned in JSON format
  },
  error:ServiceFailed
});

JSONP是一种避免交叉起源ajax请求的机制,JSONP请求将始终使用GET发送。

您应该将数据类型设置为您期望从API获得的数据类型。

在进行交叉原始ajax请求时,浏览器将首先发出OPTIONS请求。这称为预检,您可以在此处详细了解:MDN - CORS - Preflighted requests

要启用此功能,您需要为IEmployeeService.cs中的OPTIONS方法创建一个路由,并返回一个200的空响应。您的配置文件似乎正在设置正确的标题。

答案 1 :(得分:1)

如果您获得405(2011年的新Web标准,请参阅原始RFC here),则需要启用CORS

使用WCF启用CORS并不是特别容易,因为您必须做的不仅仅是在web.config中尝试添加自定义标头。只需编辑web.config就足以支持ASP.NET Web API,但如果这不是您正在处理的内容,那么您需要添加大量自定义代码以允许OPTIONS标头,在您的Web服务中。幸运的是,人们过去曾这样做过。 (基本上,您需要创建一个消息检查器,然后创建一些使用消息检查器类添加所需标头的端点行为。)

添加必要的消息检查程序的最简单方法是使用服务主机工厂,例如this article末尾链接的服务主机工厂。将服务主机工厂引用添加到.svc文件以及实现消息检查器的两个必要文件之后,您将成功启用CORS。只要您收到405错误,您就无法成功启用CORS。

有关实施的更多参考,请参阅http://enable-cors.org/server_wcf.html上的示例。