简体   繁体   English

没有参数或UriTemplate的WebGet失败

[英]WebGet with No Parameters or UriTemplate Fails

I have a RESTful WCF web service with the following API: 我有一个RESTful WCF Web服务,其中包含以下API:

[WebGet(ResponseFormat = WebMessageFormat.Json)]
MyResponseContract GetFileInfo();

When attempting to hit endpoint (using SOAPUI) I see the following error message: 尝试命中端点(使用SOAPUI)时,我看到以下错误消息:

The server encountered an error processing the request. 服务器遇到处理请求的错误。 Please see the service help page for constructing valid requests to the service. 请参阅服务帮助页面以构建对服务的有效请求。

I have SOAPUI set to hit it with a GET method call. 我有SOAPUI设置为使用GET方法调用命中它。 When I switch it to a POST with no body, it fails with the following message: 当我将其切换到没有正文的POST时,它会失败并显示以下消息:

Method not allowed. 方法不允许。

This makes perfect sense: can't hit a GET with a POST. 这很有道理:无法通过POST获得GET。 So I updated my code as follows: 所以我更新了我的代码如下:

[WebInvoke(ResponseFormat = WebMessageFormat.Json)]
MyResponseContract GetFileInfo();

And now I call it from SOAPUI with a POST method and it works. 现在我使用POST方法从SOAPUI调用它并且它可以工作。 Curious. 好奇。 So I now change my code as follows: 所以我现在更改我的代码如下:

[WebInvoke(ResponseFormat = WebMessageFormat.Json, Method = "GET")]
MyResponseContract GetFileInfo();

I've seen in a few posts that this is essentially equivalent to a WebGet attribute. 我在一些帖子中看到,这基本上等同于WebGet属性。 This also does not work. 这也行不通。

So my question is: why doesn't this work as a WebGet even though I am not accepting parameters or using a custom UriTemplate? 所以我的问题是:即使我不接受参数或使用自定义UriTemplate,为什么它不能作为WebGet工作?

The Url I'm trying to hit it with (it's hosted locally in IIS) is: 我试图点击它(它在IIS本地托管)的Url是:

http://localhost/Utilities/API/GetFileInfo

Update Given the comments below and the given answers, I am still faced with this problem. 更新鉴于下面的评论和给出的答案,我仍然面临这个问题。 Some additional details. 一些额外的细节。

My web-layer web.config 我的web层web.config

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <customErrors mode="Off" />
  </system.web>
  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    <standardEndpoints>
      <webHttpEndpoint>
        <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true" maxReceivedMessageSize="10000000" />
      </webHttpEndpoint>
    </standardEndpoints>
    <behaviors>
      <endpointBehaviors>
        <behavior name="exampleBehavior">
          <callbackDebug includeExceptionDetailInFaults="true" />
          <enableWebScript />
          <webHttp helpEnabled="true" />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <bindings>
      <webHttpBinding>
        <binding name="WebHttpBinding" maxReceivedMessageSize="10000000" />
      </webHttpBinding>
    </bindings>
    <client>    
      <endpoint address="http://LOCALHOST/Utilities.AppService/API"
                binding="webHttpBinding" bindingConfiguration="WebHttpBinding"
                contract="Utilities.Common.API.IMyApi"
                behaviorConfiguration="exampleBehavior" />
    </client>
  </system.serviceModel>
</configuration>

My app-layer web.config: 我的app-layer web.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <customErrors mode="Off" />
  </system.web>
  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    <standardEndpoints>
      <webHttpEndpoint>
        <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true" maxReceivedMessageSize="10000000" />
      </webHttpEndpoint>
    </standardEndpoints>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE" type="System.Web.Handlers.TransferRequestHandler" resourceType="Unspecified" requireAccess="Script" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
  </system.webServer>
</configuration>

My service interface 我的服务界面

[ServiceContract(Namespace = "API")]
public interface IMyApi
{    
    [WebGet]
    MyResponseContract GetFileInfo();
}

My web-layer implementation 我的网络层实现

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MyApiWebService : ClientBase<IMyApi>, IMyApi
{
    public MyResponseContract GetFileInfo()
    {
        return Channel.GetFileInfo();
    }
}

My app-layer implementation 我的app层实现

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MyApiAppService : IMyApi
{
    public MyResponseContract GetFileInfo()
    {
        return new MyResponseContract();
    }
}

My web-layer Global.asax: 我的网页层Global.asax:

    protected void Application_Start(object sender, EventArgs e)
    {
        RouteTable.Routes.Add(new ServiceRoute("API", new WebServiceHostFactory(), typeof(MyApiWebService)));
    }

My app-layer Global.asax: 我的应用层Global.asax:

    protected void Application_Start(object sender, EventArgs e)
    {
        RouteTable.Routes.Add(new ServiceRoute("API", new WebServiceHostFactory(), typeof(MyApiAppService)));
    }

I'm not sure how much more detail I can provide. 我不确定我能提供多少细节。 As you can see, given the solutions provided, I have implemented everything suggested to no avail. 正如您所看到的,鉴于提供的解决方案,我已经实施了一切无效的建议。 Whether I am trying to hit this WebGet method by placing the web layer service url in the browser, or using SOAPUI, or trying to hit it with a C# unit test using a service client, I am unable to use WebGet . 无论我是通过将Web层服务URL放在浏览器中,还是使用SOAPUI来尝试触及此WebGet方法,或者尝试使用服务客户端使用C#单元测试来命中它,我都无法使用WebGet Thanks again for all of your help. 再次感谢您的帮助。

And interesting note is that the App-layer URL works. 有趣的是,应用层URL工作正常。 But the web layer does not. 但是网络层没有。 So: 所以:

localhost/Utilities.AppService/API/GetFileInfo

works, whereas 工作,而

localhost/Utilities.WebService/API/GetFileInfo

does not. 才不是。

So this may not have been obvious until I updated recently, but I have two RESTful services that communicate with each other but live in separate domains. 所以在我最近更新之前这可能不是很明显,但我有两个RESTful服务,它们彼此通信但是生活在不同的域中。 The Web-Layer service is the first point of contact and the App-Layer service is the actual work-doer. Web层服务是第一个联系点,App层服务是实际的工作实践者。 This being the case, I was able to debug a bit further and found that the actual exception was a 405 (Method Not Allowed) on the call from the Web to App layers. 在这种情况下,我能够进一步调试,发现从Web到App层的调用实际异常是405(Method Not Allowed)。 I found this link after much digging that solved my issue. 我经过多次挖掘后发现这个链接解决了我的问题。

When using ClientBase<> as you method of communication between services you essentially need to reestablish the operation context between calls. 当使用ClientBase<>作为服务之间的通信方法时,您基本上需要重新建立调用之间的操作上下文。 Otherwise everything becomes a POST and, as such, only POSTs work. 否则一切都变成了POST,因此只有POST工作。

I hope this helps others, and I greatly appreciate everyone's help in debugging this. 我希望这有助于其他人,我非常感谢大家帮忙调试这个。

To demonstrate what this looks like, here is what my updated, working web service implementation looks like: 为了演示这看起来是什么,以下是我更新的,有效的Web服务实现:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MyApiWebService : ClientBase<IMyApi>, IMyApi
{
    public MyResponseContract GetFileInfo()
    {
        MyResponseContract output = null;

        using(var context = new OperationContext(Channel as IContextChannel))
        {
            output = Channel.GetFileInfo();
        }

        return output;
    }
}

The .NET WCF web service by default is set up to send text encoded SOAP messages. 默认情况下,.NET WCF Web服务设置为发送文本编码的SOAP消息。 This means that the HTTP method is POST and there are required headers to tell the service what method to call. 这意味着HTTP方法是POST,并且需要标头来告诉服务要调用哪种方法。

I created a quick example using your service endpoint and here is the request generated from fiddler to talk to that endpoint. 我使用您的服务端点创建了一个快速示例,这里是fiddler生成的与该端点通信的请求。

POST http://localhost/Utilities/API/GetFileInfo/Service1.svc HTTP/1.1
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://tempuri.org/IService1/GetFileInfo"
Host: localhost:8888
Content-Length: 136
Expect: 100-continue
Connection: Keep-Alive

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><GetFileInfo xmlns="http://tempuri.org/"/></s:Body></s:Envelope>

Getting back a response of 回复一下

HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 398
Content-Type: text/xml; charset=utf-8
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcV29ya1xFSVAgV29ya1xRdWVzdGlvbnNcV0NGR2V0VGVzdFxTZXJ2aWNlMS5zdmM=?=
X-Powered-By: ASP.NET
Date: Thu, 21 May 2015 19:47:49 GMT

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><GetFileInfoResponse xmlns="http://tempuri.org/"><GetFileInfoResult xmlns:a="http://schemas.datacontract.org/2004/07/WCFGetTest" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><a:BoolValue>true</a:BoolValue><a:StringValue>MyResponseContract </a:StringValue></GetFileInfoResult></GetFileInfoResponse></s:Body></s:Envelope>

For you I think something in your SoapUI is not set correctly. 对于你,我认为你的SoapUI中的某些东西设置不正确。 Either the post data or the headers. 邮寄数据或标题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM