远程服务器返回一个错误:(405) 方法不允许。WCF REST服务。

8

这个问题已经在其他地方提出过,但那些解决方案并不适用于我的问题。

这是我的服务。

[WebInvoke(UriTemplate = "", Method = "POST")]
public SampleItem Create(SampleItem instance)
{
    // TODO: Add the new instance of SampleItem to the collection
    // throw new NotImplementedException();
    return new SampleItem();
}

我有一个调用上述服务的代码。
XElement data = new XElement("SampleItem",
                             new XElement("Id", "2"),
                             new XElement("StringValue", "sdddsdssd")
                           ); 

System.IO.MemoryStream dataSream1 = new MemoryStream();
data.Save(dataSream1);

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:2517/Service1/Create");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
// You need to know length and it has to be set before you access request stream
request.ContentLength = dataSream1.Length;

using (Stream requestStream = request.GetRequestStream())
{
    dataSream1.CopyTo(requestStream);
    byte[] bytes = dataSream1.ToArray();
    requestStream.Write(bytes, 0, Convert.ToInt16(dataSream1.Length));
    requestStream.Close();
}

WebResponse response = request.GetResponse();

我在最后一行遇到了一个异常:

远程服务器返回了一个错误:(405)方法不允许。不确定为什么会发生这种情况,我尝试将主机从VS服务器更改为IIS,但结果没有变化。如果需要更多信息,请告诉我。


1
你的路由长什么样? - M.Babcock
请添加您正在使用的任何绑定配置代码/配置。 - Drew Marsh
你正在将 contenttype 设置为 "application/x-www-form-urlencoded"。但是你正在发送 XML 数据。你能把 content type 设置为 "application/xml" 吗? - Chandermani
我没有任何绑定配置。 - Praneeth
6个回答

9

首先要知道你的REST服务的确切URL。由于你已经指定了http://localhost:2517/Service1/Create,现在只需尝试从IE打开相同的URL,你应该会得到“方法不允许”的错误提示,因为你的Create方法是定义为WebInvoke的,而IE执行的是WebGet。

现在,请确保你的客户端应用程序中有SampleItem,并且与服务器上的相同命名空间定义,或者确保你正在构建的XML字符串具有适当的命名空间,以便服务可以识别示例对象的XML字符串可以反序列化回服务器上的对象。

我在我的服务器上定义了SampleItem,如下所示:

namespace SampleApp
{
    public class SampleItem
    {
        public int Id { get; set; }
        public string StringValue { get; set; }            
    }    
}

我的SampleItem对应的XML字符串如下所示:
<SampleItem xmlns="http://schemas.datacontract.org/2004/07/SampleApp" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Id>6</Id><StringValue>from client testing</StringValue></SampleItem>

现在我使用以下方法向REST服务执行POST:

private string UseHttpWebApproach<T>(string serviceUrl, string resourceUrl, string method, T requestBody)
        {
            string responseMessage = null;
            var request = WebRequest.Create(string.Concat(serviceUrl, resourceUrl)) as HttpWebRequest;
            if (request != null)
            {
                request.ContentType = "application/xml";
                request.Method = method;
            }

            //var objContent = HttpContentExtensions.CreateDataContract(requestBody);
            if(method == "POST" && requestBody != null)
            {
                byte[] requestBodyBytes = ToByteArrayUsingDataContractSer(requestBody);
                request.ContentLength = requestBodyBytes.Length;
                using (Stream postStream = request.GetRequestStream())
                    postStream.Write(requestBodyBytes, 0, requestBodyBytes.Length);                    
            }

            if (request != null)
            {
                var response = request.GetResponse() as HttpWebResponse;
                if(response.StatusCode == HttpStatusCode.OK)
                {
                    Stream responseStream = response.GetResponseStream();
                    if (responseStream != null)
                    {
                        var reader = new StreamReader(responseStream);

                        responseMessage = reader.ReadToEnd();                        
                    }
                }
                else
                {
                    responseMessage = response.StatusDescription;
                }
            }
            return responseMessage;
        }

private static byte[] ToByteArrayUsingDataContractSer<T>(T requestBody)
        {
            byte[] bytes = null;
            var serializer1 = new DataContractSerializer(typeof(T));            
            var ms1 = new MemoryStream();            
            serializer1.WriteObject(ms1, requestBody);
            ms1.Position = 0;
            var reader = new StreamReader(ms1);
            bytes = ms1.ToArray();
            return bytes;
        }

现在我按照如下所示调用上述方法:
SampleItem objSample = new SampleItem();
objSample.Id = 7;
objSample.StringValue = "from client testing";
string serviceBaseUrl = "http://localhost:2517/Service1";
string resourceUrl = "/Create";
string method="POST";

UseHttpWebApproach<SampleItem>(serviceBaseUrl, resourceUrl, method, objSample);

我在客户端也定义了SampleItem对象。如果你想在客户端构建XML字符串并传递,那么可以使用以下方法:

private string UseHttpWebApproach(string serviceUrl, string resourceUrl, string method, string xmlRequestBody)
            {
                string responseMessage = null;
                var request = WebRequest.Create(string.Concat(serviceUrl, resourceUrl)) as HttpWebRequest;
                if (request != null)
                {
                    request.ContentType = "application/xml";
                    request.Method = method;
                }

                //var objContent = HttpContentExtensions.CreateDataContract(requestBody);
                if(method == "POST" && requestBody != null)
                {
                    byte[] requestBodyBytes = ASCIIEncoding.UTF8.GetBytes(xmlRequestBody.ToString());
                    request.ContentLength = requestBodyBytes.Length;
                    using (Stream postStream = request.GetRequestStream())
                        postStream.Write(requestBodyBytes, 0, requestBodyBytes.Length);                    
                }

                if (request != null)
                {
                    var response = request.GetResponse() as HttpWebResponse;
                    if(response.StatusCode == HttpStatusCode.OK)
                    {
                        Stream responseStream = response.GetResponseStream();
                        if (responseStream != null)
                        {
                            var reader = new StreamReader(responseStream);

                            responseMessage = reader.ReadToEnd();                        
                        }
                    }
                    else
                    {
                        responseMessage = response.StatusDescription;
                    }
                }
                return responseMessage;
            }

上述方法的调用示例如下:

string sample = "<SampleItem xmlns=\"http://schemas.datacontract.org/2004/07/XmlRestService\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><Id>6</Id><StringValue>from client testing</StringValue></SampleItem>";   
string serviceBaseUrl = "http://localhost:2517/Service1";
string resourceUrl = "/Create";
string method="POST";             
UseHttpWebApproach<string>(serviceBaseUrl, resourceUrl, method, sample);

注意:确保您的URL正确无误。

你的服务是如何托管的?你在 global.asax 中有一个入口吗?同时检查一下是否启用了帮助页面,从中尝试找到你要发布的方法的 URL,并确保该 URL 正确无误。 - Rajesh
帮助功能正在工作,我可以在浏览器中看到服务,并且可以在浏览器中使用GET方法。服务是通过VS服务器托管的,并且我在global.asax中注册了路由。 - Praneeth
你能否删除空的URITemplate属性并查看是否有效。此外,在POST期间,您的帮助页面将提供CREATE方法的URL。 - Rajesh
你能在URI中仅使用那个,而不需要任何Create吗? - Rajesh
我在URI中没有创建。 - Praneeth
显示剩余2条评论

4

您是第一次运行WCF应用程序吗?

请运行以下命令以注册WCF。

"%WINDIR%\Microsoft.Net\Framework\v3.0\Windows Communication Foundation\ServiceModelReg.exe" -r

2
在使用 VS 2010 .NET 4.0、IIS 7.5 WCF 和返回 JSON 响应的 REST 方式上花费了2天后,我终于通过阅读这里的“进一步调查”https://sites.google.com/site/wcfpandu/useful-links 解决了问题。生成的 Web 服务客户端代码文件 Reference.cs 没有用 [WebGet()] 来标识 GET 方法,所以尝试进行 POST,因此出现InvalidProtocol, 405 Method Not Allowed.问题。然而,每次刷新服务引用时,该文件都会重新生成,并且您还需要引用 System.ServiceModel.Web 的 dll,才能使用 WebGet 属性。
因此,我决定手动编辑 Reference.cs 文件并保留一份副本。下次刷新它时,我将合并我的 WebGet() 回去。在我看来,这是 svcutil.exe 的一个错误,它无法识别某些服务方法只是 POST 而不是 GET,即使 WCF IIS Web 服务发布的 WSDL 和 HELP 知道哪些方法是 POSTGET???我已经向 Microsoft Connect 报告了此问题。

0
我已经解决了这个问题,因为您的服务是由用户名和密码进行安全验证的,请尝试在请求中设置用户名和密码,它将正常工作。祝好运!

0
在我遇到的情况中,还有另一个原因:基础代码试图执行 WebDAV PUT 操作。(如果需要,可以配置此特定应用程序以启用此功能;但是,我不知道该功能已被启用,但必要的 Web 服务器环境未设置。希望这可以帮助其他人。

0
当我遇到这个问题时,我只是简单地在函数名中添加了单词post,这解决了我的问题。也许它能帮助你们中的一些人。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接