Wcf 中的 WebInvoke POST“方法不允许”

Posted

技术标签:

【中文标题】Wcf 中的 WebInvoke POST“方法不允许”【英文标题】:WebInvoke POST "Method not allowed" in Wcf 【发布时间】:2013-09-06 06:25:03 【问题描述】:

我的 Rest wcf 服务如下...

[ServiceContract]
public interface IWinPhoneService


[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "getkpimeasuredata", Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped)]
List<MeasureData> GetKpiMeasureData(DomainData data);


[OperationContract]
[WebGet(UriTemplate = "getdata/value", ResponseFormat = WebMessageFormat.Json)]
string GetData(string value);


// TODO: Add your service operations here


[DataContract]
public class DomainData

    [DataMember]
    public int? KPIId
    
        get;
        set ;
    

[DataMember]
public int? ScorecardId

    get;
    set;


[DataMember]
public short? CumulativeMonth

    get;
    set;


[DataMember]
public int? EngineeringOrgId

    get;
    set;


[DataMember]
public int? BusinessOrgId

    get;
    set;

[DataMember]
public int? DataValuetypeId

    get;
    set;



当我使用 Restsharp 使用此服务时,如下所示

string URL = "http://<servername>:8085/WinPhoneService.svc";

            RestClient client = new RestClient(URL);

            RestRequest request = new RestRequest("getkpimeasuredata",Method.POST);
            DomainData data = new DomainData();
            data.KPIId = 1006;
            data.ScorecardId = 3;
            data.EngineeringOrgId = 11;
            data.DataValuetypeId = 1;
            data.CumulativeMonth = 463;
            data.BusinessOrgId = 1;

            string json = Newtonsoft.Json.JsonConvert.SerializeObject(data);

            json = "\"data\" : " + json + "";

            request.AddParameter("application/json; charset=utf-8", json, ParameterType.RequestBody);
            request.RequestFormat = DataFormat.Json;
 client.ExecuteAsync(request, response =>
            
                if (response.StatusCode == HttpStatusCode.OK)
                



                
                else
                
                    //NOK
                
            );

甚至尝试了如下的webget方法..

 RestClient client1 = new RestClient(URL);
            RestRequest request1 = new RestRequest(string.Format("getdata/0", 1), Method.GET);
            request1.RequestFormat = DataFormat.Json;

            var x = client1.ExecuteAsync(request1, response =>
                
                    if (response.StatusCode == HttpStatusCode.OK)
                    

                    
                );

我能够将 response.StatusCode 设置为 NotFound,即使我检查了提琴手 服务根本没有命中,并且当我验证了服务 URL 时 在作曲家我得到错误为 "HTTP/1.1 405 方法不允许"

甚至当我尝试使用如下 Webclient 时

string URL = "http://<servername>:8085/WinPhoneService.svc";
            WebClient wclient = new WebClient();
            wclient.UseDefaultCredentials = true;
            wclient.Headers["Content-Type"] = "application/json";


            DomainData kpidata = new DomainData();
            data.KPIId = 1006;
            data.ScorecardId = 3;
            data.EngineeringOrgId = 11;
            data.DataValuetypeId = 1;
            data.CumulativeMonth = 463;
            data.BusinessOrgId = 1;

            string json = SerializeJson(kpidata);
            String str = wclient.UploadString(new Uri(URL ),"getkpimeasuredata",json);

即使在这里我得到“HTTP/1.1 405 Method Not Allowed”,但至少在这种情况下它如fiddler所示命中服务

PFB 相同的 webconfig...

<?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=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation>
      <assemblies>
        <add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      </assemblies>
    </compilation>
    <!--<httpRuntime targetFramework="4.0" />-->
  </system.web>
  <system.serviceModel>
    <bindings>
      <webHttpBinding>
        <binding name="webCorpBinding">
          <!--<security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows"></transport>
          </security>-->
        </binding>
      </webHttpBinding>

    </bindings>
    <behaviors>

      <endpointBehaviors>
        <behavior name="RESTCorpBehavior">
          <webHttp/>
        </behavior>

      </endpointBehaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true"  />
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name="WinPhoneService.WinPhoneService">
        <endpoint name="WinPhoneServiceeCorp" address="" binding="webHttpBinding" bindingConfiguration="webCorpBinding" behaviorConfiguration="RESTCorpBehavior"
         contract="WinPhoneService.IWinPhoneService" />
      </service>
    </services>
    <!--<protocolMapping>
      <add binding="basicHttpsBinding" 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>-->


  <connectionStrings>
    <add name="ScaasEntities" connectionString="metadata=res://*/Scaas.csdl|res://*/Scaas.ssdl|res://*/Scaas.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=<servername>;initial catalog=<catalog>;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
  </entityFramework>
</configuration>

请帮助我解决同样的问题..

我在win8手机应用中使用的功能是

public async void  LoadKpiData()
        
                       string URL = "http://rr1biscdevsql01:8085/WinPhoneService.svc/getkpimeasuredata;
            WebClient wclient = new WebClient();
            wclient.UseDefaultCredentials = true;
            wclient.Headers["Content-Type"] = "application/json";

            DomainData kpidata = new DomainData();
            kpidata.KPIId = 1006;
            kpidata.ScorecardId = 3;
            kpidata.EngineeringOrgId = 11;
            kpidata.DataValuetypeId = 1;
            kpidata.CumulativeMonth = 463;
            kpidata.BusinessOrgId = 1;

            string json = SerializeJson(kpidata);
            wclient.UploadStringAsync(new Uri(URL), json);

            wclient.UploadStringCompleted += (s, e) =>
                

                ;

        

当我检查 Restclient 调用的响应时,出现如下错误

 "ErrorCode":"1001","ErrorMessage":"System.Data.EntityCommandExecutionException: The data reader is incompatible with the specified 'ScaasModel.GetKPIMeasureData_Result'. A member of the type, 'ParamName', does not have a corresponding column in the data reader with the same name.\u000d\u000a   at System.Data.Query.InternalTrees.ColumnMapFactory.GetColumnMapsForType(DbDataReader storeDataReader, EdmType edmType, Dictionary`2 renameList)\u000d\u000a   at System.Data.Query.InternalTrees.ColumnMapFactory.CreateColumnMapFromReaderAndType(DbDataReader storeDataReader, EdmType edmType, EntitySet entitySet, Dictionary`2 renameList)\u000d\u000a   at System.Data.Query.InternalTrees.ColumnMapFactory.CreateFunctionImportStructuralTypeColumnMap(DbDataReader storeDataReader, FunctionImportMapping mapping, EntitySet entitySet, StructuralType baseStructuralType)\u000d\u000a   at System.Data.EntityClient.EntityCommandDefinition.FunctionColumnMapGenerator.System.Data.EntityClient.EntityCommandDefinition.IColumnMapGenerator.CreateColumnMap(DbDataReader reader)\u000d\u000a   at System.Data.Objects.ObjectContext.CreateFunctionObjectResult[TElement](EntityCommand entityCommand, EntitySet entitySet, EdmType edmType, MergeOption mergeOption)\u000d\u000a   at System.Data.Objects.ObjectContext.ExecuteFunction[TElement](String functionName, MergeOption mergeOption, ObjectParameter[] parameters)\u000d\u000a   at System.Data.Objects.ObjectContext.ExecuteFunction[TElement](String functionName, ObjectParameter[] parameters)\u000d\u000a   at ScaasWinPhone.Model.ScaasEntities.GetKPIMeasureData(Nullable`1 kPIID, Nullable`1 scorecardID, Nullable`1 cumulativeMonthCount, Nullable`1 engineeringOrgID, Nullable`1 businessOrgID, Nullable`1 dataValueTypeID, Nullable`1 debug, ObjectParameter errorText)\u000d\u000a   at ScaasWinphoneRepository.ScaasRepository.GetKpiMeasureData(Nullable`1 kpiId, Nullable`1 scorecardId, Nullable`1 cumulativeMonth, Nullable`1 engineeringOrgId, Nullable`1 businessOrgId, Nullable`1 dataValuetypeId)\u000d\u000a   at SCaaSWinPhoneService.SCaaSWinPhoneService.GetKpiMeasureData(KpiDomainData kpidata)"

拉杰什 当我添加 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] 在服务中和

<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>

在 webconfig 中出现错误,因为服务无法激活,因为它不支持 ASP.NET 兼容性。为此应用程序启用了 ASP.NET 兼容性。在 web.config 中关闭 ASP.NET 兼容模式,或将 AspNetCompatibilityRequirements 属性添加到服务类型,并将 RequirementsMode 设置为“允许”或“必需”。

实际上,当我在 localhost 中运行服务时它工作正常,但是当我托管服务时它抛出错误..请帮助....

【问题讨论】:

您能否先尝试通过从浏览器访问 GET 资源并获取响应来查看是否可以访问 REST 服务。确保在 Fiddler 中捕获请求,并请发布您的 Fiddler 原始请求 是的,当在浏览器 http://:8085/WinPhoneService.svc/getdata/1 中调用时,我得到的 json 结果为“您输入:1” 当我为 URL 提供“http://:8085/WinPhoneService.svc/getkpimeasuredata”而不是在 Uploadstring 中提及方法名称时...如果我使用 webclient 但如果我使用 Restclient 它根本不工作。请帮助 如果您尝试通过浏览器访问 getkipmeasuredata,您应该遇到一些异常,因为您的方法配置为 POST 而不是 GET。您能否尝试使用 Fiddler 捕获原始请求并将其发布给我们以查看 POST 请求。 我没有通过浏览器从代码本身访问getkipmeasuredata我正在尝试......正如我在提琴手中所说,当我使用Restclient时我没有收到任何服务调用......当我使用webclient和修改后的URL参数为 http://:8085/WinPhoneService.svc/getkpimeasuredata 而不是在uploadstring中传递方法名称一切正常......但我需要Restclient中的解决方案。请帮助 【参考方案1】:
[WebInvoke(... , Method = "POST" ... )]List<MeasureData> GetKpiMeasureData(DomainData data);

上面的代码你使用了 POST 方法,但是你必须使用 GET 方法,因为 POST 方法只用于添加数据。

Http 动词是 POST 、 GET 、 Delete 和 PUT(Update) 。你必须先学习。

I used Get method and RestSharp.dll for my project 如果您想将我的项目用于 POST 方法,您可以使用以下代码

客户端

 var client1 = new RestClient("http://localhost:61111/Service1.svc");
            var request1 = new RestRequest("/AddPerson", Method.POST);
            Person person1 = new Person();
            person1.PersonID = 2;
            person1.Name = "Robert";
            person1.SurName = "Dan";
            JsonSerializer serial = new JsonSerializer();

            string temp = serial.Serialize(person1);
            Console.WriteLine(temp);
            Person tempPerson1 = new javascriptSerializer().Deserialize<Person>(temp);
            Console.WriteLine(tempPerson1.PersonID + " " + tempPerson1.Name + " " + tempPerson1.SurName);

服务器端

public class Service1 : IService1
       
    private Person person = new Person()  PersonID = 1, Name = "John", SurName = "Albert" ;
    public Person GetPerson()
    
        return person;
    
    public Person AddPerson(Person person)
    
        return person;
    



[ServiceContract]
public interface IService1


    [OperationContract]
    [WebInvoke(Method="GET", ResponseFormat = WebMessageFormat.Json, UriTemplate = "/GetPerson")]
    Person GetPerson();
    [OperationContract]
    [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "/AddPerson")]
    Person AddPerson(Person person);

【讨论】:

【参考方案2】:

看看这段代码

我的服务器代码如下

[ServiceContract]
    public interface IWinPhoneService
    
        [OperationContract]
        [WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "getkpimeasuredata")]
        List<String> GetKpiMeasureData(DomainData data);
    

[DataContract]
    public class DomainData

    [DataMember]
    public int? KPIId  get; set; 

    [DataMember]
    public int? ScorecardId  get; set; 

    [DataMember]
    public short? CumulativeMonth  get; set; 

    [DataMember]
    public int? EngineeringOrgId  get; set; 

    [DataMember]
    public int? BusinessOrgId  get; set; 

    [DataMember]
    public int? DataValuetypeId  get; set; 

现在我的接口实现如下

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class WinPhoneService : IWinPhoneService
    
        public List<string> GetKpiMeasureData(DomainData data)
        
            if (data != null)
            
                return new List<string>()  "Sample 1","Sample 2";
            
            return new List<string>() "No data recieved";
        
    

用于端点元素配置的服务器端 web.config

<system.serviceModel>
<services>
    <service name="WinPhoneService.WinPhoneService">
            <endpoint address="" binding="webHttpBinding" behaviorConfiguration="web" bindingConfiguration="defaultRestJsonp" contract="WinPhoneService.IWinPhoneService">
            </endpoint>
          </service>
    </services>
    <behaviors>
    <endpointBehaviors>
            <behavior name="web">
              <webHttp />
              <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
            </behavior>        
    </endpointBehaviors> 
    </behaviors>
    <bindings>   
    <webHttpBinding>
            <binding name="defaultRestJsonp" crossDomainScriptAccessEnabled="true">
              <readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxDepth="64" maxNameTableCharCount="2147483647" />
              <security mode="None" />
            </binding>
  </webHttpBinding>
  </bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />     
 </system.serviceModel>  

现在有了以上所有设置,使用 RestSharpClient 在下面找到我的客户端代码:

private static string ToStringUsingDataContractJsonSer<T>(T requestBody)
        
            var serializer = new DataContractJsonSerializer(typeof(T));
            var ms = new MemoryStream();
            serializer.WriteObject(ms, requestBody);
            ms.Position = 0;
            var reader = new StreamReader(ms);
            return reader.ReadToEnd();
        

private string UseRestSharpApproach(string serviceBaseUrl, string resourceUrl, Method method, object requestBody)
        
            var client = new RestClient();
            client.BaseUrl = serviceBaseUrl;
            var request = new RestRequest(method)  DateFormat = DataFormat.Xml.ToString(), Resource = resourceUrl ;
            request.AddParameter("application/json", requestBody, ParameterType.RequestBody);            
            var response = client.Execute(request);

            string responseString;
            if (response.StatusCode == HttpStatusCode.OK)
            
                responseString = HttpUtility.htmlDecode(response.Content);
            
            else
            
                responseString = response.StatusDescription + " --------------------" + HttpUtility.HtmlDecode(response.Content);
            
            return responseString;
        

public void CallRESTService()

       UseRestSharpApproach(serviceBaseUrl, resourceUrl, Method.POST, ToStringUsingDataContractJsonSer<DomainData>(objDomainData));

确保在客户端使用时的 DomainData 对象与在服务器上使用的名称空间相同,以便序列化和反序列化顺利进行。

现在我来自 Fiddler 的原始请求如下所示:

POST http://servername/Sample/WinPhoneService.svc/GetKpiMeasureData HTTP/1.1
Accept: application/json, application/xml, text/json, text/x-json, text/javascript, text/xml
User-Agent: RestSharp 102.0.0.0
Content-Type: application/json
Host: servername
Content-Length: 112
Accept-Encoding: gzip, deflate

"BusinessOrgId":1,"CumulativeMonth":463,"DataValuetypeId":1,"EngineeringOrgId":11,"KPIId":1006,"ScorecardId":3

响应如下:

HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 23
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS
X-AspNet-Version: 4.0.30319
Set-Cookie: ASP.NET_SessionId=123450p12rvdmnh3qrx2ocip; path=/; HttpOnly
Date: Tue, 03 Sep 2013 10:11:51 GMT

["Sample 1","Sample 2"]

【讨论】:

感谢您的回复,您的 URI 模板是 getkpimeasuredata 但在您提到 GetKpiMeasureData 的 url 中,您能告诉我您如何传递 UseRestSharpApproach 函数的参数 请看这篇可能有帮助的 SO 帖子:***.com/questions/6312970/… Rajesh 实际上我还需要从 windows phone 8 项目执行休息呼叫,它是一个移动应用程序..当我使用 webclient 休息呼叫正在从控制台应用程序工作但当我从移动设备运行相同的代码时应用程序即时获取 System.Net.WebException:远程服务器返回错误:NotFound。使用异步函数时出错,请参阅上面的更新代码 您可以先尝试在同步中运行它们,看看是否有效。我不确定是否有来自 win phone 8 的模拟器供我提供样本。尝试在您的服务器上启用跟踪,然后检查跟踪文件以查看更详细的信息。当您的服务没有任何身份验证时,为什么要使用默认凭据。 实际上问题出在 winphone 8 上,无法识别托管的 wcf url,但是当我将 servicebus 集成到 Webclient 时,它正在工作(如果我提供服务总线 url 而不是托管的 wcf url)与 Webclient 而不是 Restclient ,实际上我使用实体和我使用动态sql返回结果集的sp ..我在上面编辑的问题中提到的Restclient调用中出现错误。请帮助

以上是关于Wcf 中的 WebInvoke POST“方法不允许”的主要内容,如果未能解决你的问题,请参考以下文章

WCF Webinvoke POST 给出(400)特定服务器的错误请求

自托管 WCF REST 服务 JSON POST 方法不允许

WCF 休息 WebInvoke 获取方法不起作用返回 404 错误

将 jQuery 中的 WCF 作为 JSON 使用

如何以 JSON 形式返回 WCF 服务 POST 响应

如何通过 post 将 xml 发送到 wcf 服务