WCF RESTful 应用程序 PUT、POST、DELETE 收到相同的错误:“该方法不允许。”

Posted

技术标签:

【中文标题】WCF RESTful 应用程序 PUT、POST、DELETE 收到相同的错误:“该方法不允许。”【英文标题】:WCF restful application PUT, POST, DELETE receive the same error: "the method is not allowed." 【发布时间】:2020-06-29 15:56:10 【问题描述】:

我创建了一个在 WCF 上使用 RESTFUL 架构实现的服务器。使用实体框架和 mysql DB 用 C# 编写。代码如下。 VS 不会产生任何错误,GET 方法工作正常,它从数据库输出数据。但是,所有其他方法(PUT、POST、DELETE、GetDetails)都会收到相同的错误:“不允许使用该方法。”也许你能说出我的错误是什么? 如果有几个错误,那我将不胜感激。我刚开始研究这个,所以我承认可能会有很多错误。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Web;

namespace WcfRestFullService

   [DataContract]
    public class CustomerDataContract
    
        [DataMember]
        public string Id_Cus  get; set; 
        [DataMember]
        public string FirstName_Cus  get; set; 
        [DataMember]
        public string LastName_Cus  get; set; 
        [DataMember]
        public string PhoneNum_Cus  get; set; 
        [DataMember]
        public string Email_Cus  get; set; 
    

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfRestFullService

    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "ICustomerSevice" in both code and config file together.
    [ServiceContract]
    public interface ICustomerSevice
    
          [OperationContract]
          [WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json,
              ResponseFormat = WebMessageFormat.Json, UriTemplate = "/GetAllCustomer/")]//ok
          List<CustomerDataContract> GetAllCustomer();

         [OperationContract]
         [WebGet(RequestFormat = WebMessageFormat.Json,
          ResponseFormat = WebMessageFormat.Json,
          UriTemplate = "/CustomerDetails/Id_Cus")]
         CustomerDataContract CustomerDetails(String Id_Cus);

        [OperationContract]
         [WebInvoke(Method = "DELETE", ResponseFormat = WebMessageFormat.Json,
          RequestFormat = WebMessageFormat.Json,
          BodyStyle = WebMessageBodyStyle.Bare)]
         void DeleteCustomer(String Id_Cus);

         [OperationContract]
         [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json,
          RequestFormat = WebMessageFormat.Json,
          BodyStyle = WebMessageBodyStyle.Wrapped,
          UriTemplate = "/InsertCustomer/")]//problem
         void InsertCustomer(CustomerDataContract customerDataContract);

         [OperationContract]
         [WebInvoke(Method = "PUT",ResponseFormat = WebMessageFormat.Json,
          RequestFormat = WebMessageFormat.Json,
          BodyStyle = WebMessageBodyStyle.Bare,
          UriTemplate = "/UpdateCustomer/")]//problem
         void UpdateCustomer(CustomerDataContract customerDataContract);
    


<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.8" />
    <httpRuntime targetFramework="4.8" />
  </system.web>
  <system.serviceModel>

    <services>
      <service name="WcfRestFullService.CustomerSevice"  behaviorConfiguration="serviceBehavior">
        <endpoint address=""
                  binding="webHttpBinding"
                  contract="WcfRestFullService.ICustomerSevice"
                  behaviorConfiguration="web"></endpoint>
        </service>
          </services>

    <!--<services>
      <service name="WcfRestFullService.CustomerPreferences"  behaviorConfiguration="serviceBehavior">
        <endpoint address=""
                  binding="webHttpBinding"
                  contract="WcfRestFullService.ICustomerPreferences"
                  behaviorConfiguration="web"></endpoint>
      </service>
    </services>-->


      <behaviors>
      <endpointBehaviors>
        <behavior name="web">
          <webHttp />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="serviceBehavior">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
        <behavior name="">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
      <add binding="webHttpBinding" scheme="https" />
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true" />
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Extensions.Primitives" publicKeyToken="adb9793829ddae60" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.1.2.0" newVersion="3.1.2.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Extensions.Configuration.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.1.2.0" newVersion="3.1.2.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.1.2.0" newVersion="3.1.2.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Extensions.Caching.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.1.2.0" newVersion="3.1.2.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Extensions.Options" publicKeyToken="adb9793829ddae60" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.1.2.0" newVersion="3.1.2.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.1.2.0" newVersion="3.1.2.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Extensions.DependencyInjection" publicKeyToken="adb9793829ddae60" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.1.2.0" newVersion="3.1.2.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.ComponentModel.Annotations" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.2.1.0" newVersion="4.2.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="MySql.Data" publicKeyToken="c5687fc88969c44d" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-8.0.19.0" newVersion="8.0.19.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.EntityFrameworkCore" publicKeyToken="adb9793829ddae60" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.1.2.0" newVersion="3.1.2.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.EntityFrameworkCore.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.1.2.0" newVersion="3.1.2.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Extensions.Logging" publicKeyToken="adb9793829ddae60" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.1.2.0" newVersion="3.1.2.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.5.0" newVersion="4.0.5.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Google.Protobuf" publicKeyToken="a7d26565bac4d604" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.11.4.0" newVersion="3.11.4.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="BouncyCastle.Crypto" publicKeyToken="0e99375e54769942" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-1.8.5.0" newVersion="1.8.5.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.EntityFrameworkCore.Relational" publicKeyToken="adb9793829ddae60" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.1.2.0" newVersion="3.1.2.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <entityFramework>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
      <!--<provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6, Version=6.10.9.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d">
      </provider>-->
      <provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.EntityFramework, Version=8.0.19.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
    </providers>
  </entityFramework>
  <connectionStrings>
    <add name="MySQLEntities" connectionString="metadata=res://*/Model.Model.csdl|res://*/Model.Model.ssdl|res://*/Model.Model.msl;provider=MySql.Data.MySqlClient;provider connection string=&quot;server=localhost;user id=root;password=l10ksfnq5h2c;database=chik-chak&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>
</configuration>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using MySql.Data;
using System.Data.Entity;

using WcfRestFullService.Model;

namespace WcfRestFullService

    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "CustomerSevice" in code, svc and config file together.
    // NOTE: In order to launch WCF Test Client for testing this service, please select CustomerSevice.svc or CustomerSevice.svc.cs at the Solution Explorer and start debugging.
    public class CustomerSevice : ICustomerSevice
    
        MySQLEntities dc;
        public CustomerSevice()
        
            dc = new MySQLEntities();
        

        public List<CustomerDataContract> GetAllCustomer()
        
            var query = (from a in dc.customers
                         select a).Distinct();

            List<CustomerDataContract> CustomersList = new List<CustomerDataContract>();

            query.ToList().ForEach(x =>
            
                CustomersList.Add(new CustomerDataContract
                
                    Id_Cus = Convert.ToString(x.Id_Cus),
                    FirstName_Cus = x.FirstName_Cus,
                    LastName_Cus = x.LastName_Cus,
                    PhoneNum_Cus = x.PhoneNum_Cus.ToString(),
                    Email_Cus = x.Email_Cus,
                );
            );
            return CustomersList;
        

        public CustomerDataContract CustomerDetails(string Id_Cus)
        
            CustomerDataContract Cust = new CustomerDataContract();
            try
            
                var query = (from a in dc.customers
                             where a.Id_Cus.Equals(Id_Cus)
                             select a).Distinct().FirstOrDefault();
                Cust.Id_Cus = query.Id_Cus.ToString();
                Cust.FirstName_Cus = query.FirstName_Cus;
                Cust.LastName_Cus = query.LastName_Cus;
                Cust.PhoneNum_Cus = query.PhoneNum_Cus.ToString();
                Cust.Email_Cus = query.Email_Cus;
            
            catch (Exception ex)
            
                throw new FaultException<string>(ex.Message);
            
            return Cust;
        

           // DELETE

          public void DeleteCustomer(string Id_Cus) 
          
              MySQLEntities Cust = new MySQLEntities(); //check the file Model.edmx->ModelContext.tt->MySQLEntitys

              int k = Convert.ToInt32(Id_Cus);
              customer cur = (from n in dc.customers
                           where n.Id_Cus == k
                           select n).First();
              Cust.customers.Remove(cur);
              Cust.SaveChanges();
          

          //Insert/POST

          public void InsertCustomer(CustomerDataContract customerDataContract)
          
            MySQLEntities Cust = new MySQLEntities();
            customer cust = new customer();

              cust.Id_Cus = Convert.ToInt32(customerDataContract.Id_Cus);
              cust.FirstName_Cus = customerDataContract.FirstName_Cus;
              cust.LastName_Cus = customerDataContract.LastName_Cus;
              cust.PhoneNum_Cus = Convert.ToInt32(customerDataContract.PhoneNum_Cus);
              cust.Email_Cus = customerDataContract.Email_Cus;
              Cust.customers.Add(cust);
              Cust.SaveChanges();
          

            //Update/PUT
          public void UpdateCustomer(CustomerDataContract customerDataContract)
          
            //using (CustomerDataContract Cust = new CustomerDataContract())
            using (MySQLEntities Cust = new MySQLEntities()) 
            
                  customer cust = Cust.customers.Where(n => n.Id_Cus == (Convert.ToInt32(customerDataContract.Id_Cus))).First();

                  cust.Id_Cus =Convert.ToInt32(customerDataContract.Id_Cus);
                  cust.FirstName_Cus = customerDataContract.FirstName_Cus;
                  cust.LastName_Cus = customerDataContract.LastName_Cus;
                  cust.PhoneNum_Cus =Convert.ToInt32(customerDataContract.PhoneNum_Cus);
                  cust.Email_Cus = customerDataContract.Email_Cus;

                  Cust.SaveChanges();
            
          
    

namespace WcfRestFullService.Model

    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;

    public partial class MySQLEntities : DbContext
    
        public MySQLEntities()
            : base("name=MySQLEntities")
        
        

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        
            throw new UnintentionalCodeFirstException();
        

        public virtual DbSet<customer> customers  get; set; 
        public virtual DbSet<customerpreference> customerpreferences  get; set; 
        public virtual DbSet<dish> dishes  get; set; 
        public virtual DbSet<dishesranking> dishesrankings  get; set; 
        public virtual DbSet<ingridient> ingridients  get; set; 
        public virtual DbSet<order> orders  get; set; 
        public virtual DbSet<restaraunt> restaraunts  get; set; 
        public virtual DbSet<type_dishes> type_dishes  get; set; 
        public object Parameters  get; internal set; 
    


enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

【问题讨论】:

WCF 不是最好的工具。 【参考方案1】:

你应该知道浏览器发送的默认请求使用GetHTTP动词,而操作合约需要DELETEHTTP动词。 按 F12,网络查看请求的详细信息。 测试POST/DELETE/PUT 请求的正确方法是使用PostMan 软件(或其他一些工具,例如Fiddler)发送请求。 函数的定义。

[OperationContract]
    [WebInvoke(Method ="DELETE",RequestFormat =WebMessageFormat.Json,ResponseFormat =WebMessageFormat.Json)]
    string GetResult(string id);

Fiddler 中的请求。 如果参数是复合类型,要注意请求的数据格式。 详情见以下链接。How to call RestFul WCF POST service With Custom Object using POSTMAN or any client tool application? 如果有什么我可以帮忙的,请随时告诉我。

【讨论】:

我尝试过 Fiddler,但在 PUT 和 POST 方法中出现错误(307 和 405 错误)。并且在 DELETE 方法中“System.InvalidOperationException: '无法删除该对象,因为它在 ObjectStateManager 中找不到。” " 和 VS 中的错误:Cust.customers.Remove(cur); 它可能是什么?感谢您的最后回答:) 这是因为在数据库中没有找到要删除的对象。 customer cur = (from n in dc.customers where n.Id_Cus == k select n).First();唯一的参数应该由正文部分而不是 URL 中的查询字符串传递,因为您使用删除动词。就像上面的截图一样。 此外,您应该注意数据格式。我还没有看到customdatacontract 的定义。 ***.com/questions/58495488/… 非常感谢您的回复!是的,确实,我错误地附加了“custompreferencescontract”而不是“customdatacontract”,现在我已经编辑了所有内容并正确添加了它。我尝试按照您的建议进行操作,但在所有变体中:“localhost: 51265 / CustomerSevice.svc/GetAllCustomer /”甚至“http://localhost:51265 / CustomerSevice.svc / DeleteCustomer /”。我根据截图做所有事情。如果这对你来说没什么大不了的,也许我会在某个信使中给你发一张截图?我只是不明白我做错了什么。再次感谢您的回答。 移除 UriTemplate 并添加内容类型:Application/json。我已经在回复中添加了方法的定义。

以上是关于WCF RESTful 应用程序 PUT、POST、DELETE 收到相同的错误:“该方法不允许。”的主要内容,如果未能解决你的问题,请参考以下文章

Restful风格wcf调用2——增删改查

应用程序/json内容类型请求的Restful WCF POST问题

WCF Restful CORS 无法执行 POST

在 MVC 5 中调用 WCF Restful POST 方法

WCF RESTful 服务:如何在 POST 请求中发送长字符串参数?

Android 向 WCF RESTful WS 发布请求(JSON 参数)