远程服务器返回错误:(405) 方法不允许.WCF REST Service
本文关键字:方法 不允许 WCF Service REST 服务器 返回 错误 | 更新日期: 2023-09-27 18:30:52
这个问题已经在其他地方问过了,但这些东西不是我问题的解决方案。
这是我的服务
[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,但结果没有变化。如果您需要更多信息,请告诉我
第一件事是知道你的REST服务的确切URL。由于您已经指定了http://localhost:2517/Service1/Create
现在只需尝试从IE打开相同的URL,并且您应该获得不允许的方法,因为您的Create
方法是为WebInvoke定义的,并且IE执行WebGet。
现在,请确保在服务器上的同一命名空间中定义了客户端应用中的 SampleItem,或者确保要生成的 xml 字符串具有适当的命名空间,以便服务标识示例对象的 xml 字符串可以反序列化回服务器上的对象。
我在服务器上定义了样本项,如下所示:
namespace SampleApp
{
public class SampleItem
{
public int Id { get; set; }
public string StringValue { get; set; }
}
}
对应于我的样本项的 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);
注意:只需确保您的网址正确无误即可
您是第一次运行 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 ResponseWrapped的 REST 之后,我终于通过阅读"进一步调查时......"来破解它。这里 https://sites.google.com/site/wcfpandu/useful-links
Web 服务客户端代码生成的文件 Reference.cs 不会将GET
方法与 [WebGet()]
一起归因,因此尝试POST
它们,因此 InvalidProtocol, 405 方法不允许。 但问题是,当您刷新服务引用时,此文件会重新生成,并且您还需要 WebGet 属性的 System.ServiceModel.Web
的 dll 引用。
所以我决定手动编辑 Reference.cs 文件,并保留一份副本。 下次刷新它时,我会重新合并我的WebGet()s
。
在我看来,这是 svcutil 的一个错误.exe没有认识到某些服务方法是GET
的,而不仅仅是POST
,即使 WCF IIS Web 服务发布的 WSDL 和 HELP 确实了解哪些方法POST
和GET
??? 我已经用Microsoft连接记录了这个问题。
当它发生在我身上时,我只是简单地添加了这个词post
到函数名称,它解决了我的问题。也许它也会帮助你们中的一些人。
在我遇到的案例中,还有另一个原因:底层代码试图执行WebDAV PUT。(如果需要,此特定应用程序可配置为启用此功能;我不知道该功能已启用,但未设置必要的 Web 服务器环境。
希望这可能会对其他人有所帮助。
修复了这个问题,因为您的服务由用户名和密码的登录凭据保护,请尝试在请求中设置用户名和密码,它将正常工作。祝你好运!