Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 当遇到302响应时,为什么WCF无法调用SOAP服务?_C#_Wcf_Soap_Saas - Fatal编程技术网

C# 当遇到302响应时,为什么WCF无法调用SOAP服务?

C# 当遇到302响应时,为什么WCF无法调用SOAP服务?,c#,wcf,soap,saas,C#,Wcf,Soap,Saas,我已经编写了一个应用程序,它从调用WCF登录开始。我使用服务引用生成了客户机代码。对于在本地将其服务安装到其网络的客户端来说,它工作得很好。然而,也有一个saas环境,在这个环境中,这些相同的服务由可能的公司权力控制。在saas环境中,我被告知登录失败。通过使用Fiddler进行调查,我发现对login的服务调用返回HTML,特别是列出.asmx中所有可用方法的网页 saas环境有一个小怪癖,这可能会导致这里的问题,但我不知道如何验证这是否是问题,也不知道如果是问题,如何解决它。奇怪的是,服务器

我已经编写了一个应用程序,它从调用WCF登录开始。我使用服务引用生成了客户机代码。对于在本地将其服务安装到其网络的客户端来说,它工作得很好。然而,也有一个saas环境,在这个环境中,这些相同的服务由可能的公司权力控制。在saas环境中,我被告知登录失败。通过使用Fiddler进行调查,我发现对login的服务调用返回HTML,特别是列出.asmx中所有可用方法的网页

saas环境有一个小怪癖,这可能会导致这里的问题,但我不知道如何验证这是否是问题,也不知道如果是问题,如何解决它。奇怪的是,服务器重定向(302)呼叫

客户端代码: client.Endpoint.Address = new EndpointAddress("http://" + settings.MyURL + "/myProduct/webservices/webapi.asmx"); client.DoLogin(username, password); client.Endpoint.Address=新的端点地址(“http://“+settings.MyURL+”/myProduct/webservices/webapi.asmx”); client.DoLogin(用户名、密码);

在重定向之前,发送到服务器的原始数据包括s:Envelope XML标记。在发送到重定向服务器时,请注意丢失的s:Envelope XML标记: GET https://www.myurl.com/myProduct/webservices/webapi.asmx HTTP/1.1 Content-Type: text/xml; charset=utf-8 VsDebuggerCausalityData: uIDPo7TgjY1gCLFLu6UXF8SWAoEAAAAAQxHTAupeAkWz2p2l3jFASiUPHh+L/1xNpTd0YqI2o+wACQAA SOAPAction: "http://Interfaces.myProduct.myCompany.com/DoLogin" Accept-Encoding: gzip, deflate Host: www.gotimeforce2.com Connection: Keep-Alive 获取HTTP/1.1 内容类型:text/xml;字符集=utf-8 VsDebuggerCausalityData:UIDPO7TGJY1GCLFLU6UXF8SWAOEAAAAQXHTAUPEAKWZ2P2L3JFASIUPHH+L/1xNpTd0YqI2o+wACQAA SOAPAction:“ 接受编码:gzip,deflate 主持人:www.gotimeforce2.com 连接:保持活力

我怎么才能让这个愚蠢的东西工作呢

编辑:值得注意的是,我使用的是WCF/svcutil.exe/service-reference,而不是旧的ASMX/wsdl.exe/web-reference。否则,对于本主题的未来读者来说,Raj建议的wsdl解决方案将是一个伟大的解决方案。如果您看到这个问题并且正在使用wsdl技术,请参阅Raj的优秀答案

Edit2:在对WCF和302进行了大量研究之后,听起来它们在一起玩得不太好,似乎也没有一种简单的方法让WCF api自定义代码来处理这种情况。由于我对服务器没有控制权,所以我将其吸收并重新生成api作为web参考,并使用Raj的解决方案


Edit3:更新了标题,以便更好地反映解决方案,现在问题的原因已被了解。原始标题:为什么WCF不在重定向中包含s:Envelope?

好的,所以我在这方面做了一些挖掘,并试图复制我这边的问题。我能够复制这个问题并找到解决方案。但是,我不确定这在您的案例中应用得如何,因为这取决于与管理负载平衡器的服务器团队的接口。以下是调查结果

查看
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
您注意到HTTP状态代码302和303的说明中有以下附录

302找到

  Note: RFC 1945 and RFC 2068 specify that the client is not allowed
  to change the method on the redirected request.  However, most
  existing user agent implementations treat 302 as if it were a 303
  response, performing a GET on the Location field-value regardless
  of the original request method. The status codes 303 and 307 have
  been added for servers that wish to make unambiguously clear which
  kind of reaction is expected of the client.
303参见其他

  Note: Many pre-HTTP/1.1 user agents do not understand the 303
  status. When interoperability with such clients is a concern, the
  302 status code may be used instead, since most user agents react
  to a 302 response as described here for 303.
进一步查看
http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
您注意到以下关于HTTP状态代码302、303和307的解释

302找到: 这是与标准相矛盾的行业实践的一个例子。HTTP/1.0规范(RFC 1945)要求客户机执行临时重定向(最初描述的短语是“临时移动”),但流行浏览器使用303 See Other的功能实现了302。因此,HTTP/1.1添加了状态代码303和307以区分这两种行为。但是,一些Web应用程序和框架使用302状态代码,就好像它是303一样

303参见其他(自HTTP/1.1起): 可以使用GET方法在另一个URI下找到对请求的响应当接收到对POST(或PUT/DELETE)的响应时,应假定服务器已接收到数据,并应使用单独的GET消息发出重定向。 以下是正常客户机/服务器交互中的基本流程

307临时重定向(从HTTP/1.1开始): 在这种情况下,应该使用另一个URI重复请求;但是,将来的请求仍应使用原始URI与302的历史实现方式不同,重新发出原始请求时不允许更改请求方法。例如,一个POST请求应该使用另一个POST请求重复。

因此,根据这一点,我们能够解释WCF调用的行为,该调用在302重定向上发送GET请求而不使用s:Envelope。这无疑会在客户端失败

解决此问题的最简单方法是让服务器在响应中返回307临时重定向,而不是302 Found状态代码。在这方面,您需要管理负载平衡器上重定向规则的服务器团队的帮助。我在本地对此进行了测试,使用服务引用的服务的客户端代码无缝地执行调用,即使使用307临时重定向也是如此

事实上,您可以使用我上传到Github的解决方案来测试这一切。我对其进行了更新,以说明如何使用服务引用而不是wsdl生成的代理类来使用asmx服务

但是,如果从302 find到307临时重定向的更改在您的环境中不可行,那么我建议使用解决方案1(在响应中无论是302还是307状态代码都不会有问题)或者使用我的原始答案,通过根据配置文件中的设置直接访问正确URL的服务来解决此问题。希望这有帮助

解决方案1

如果您无法访问生产环境中的配置文件,或者您只是不想访问
public class SoapHttpClientProtocolWithRedirect :
    System.Web.Services.Protocols.SoapHttpClientProtocol
{
    protected override System.Net.WebRequest GetWebRequest(Uri uri)
    {
        if (!_redirectFixed)
        {
            FixRedirect(new Uri(this.Url));
            _redirectFixed = true;

            return base.GetWebRequest(new Uri(this.Url));
        }

        return base.GetWebRequest(uri);
    }

    private bool _redirectFixed = false;
    private void FixRedirect(Uri uri)
    {
        var request = (HttpWebRequest)WebRequest.Create(uri);
        request.CookieContainer = new CookieContainer();
        request.AllowAutoRedirect = false;
        var response = (HttpWebResponse)request.GetResponse();

        switch (response.StatusCode)
        {
            case HttpStatusCode.Redirect:
            case HttpStatusCode.TemporaryRedirect:
            case HttpStatusCode.MovedPermanently:
                this.Url = new Uri(uri, response.Headers["Location"]).ToString();
                break;
        }
    }
}
public partial class WebApiProxy : System.Web.Services.Protocols.SoapHttpClientProtocol
public partial class WebApiProxy : SoapHttpClientProtocolWithRedirect
var apiClient = new WebApiProxy(GetServiceUrl());
//TODO: Add any required headers etc.
apiClient.DoLogin(username,password);
var apiClient = new WebApiProxy(GetServiceUrl());
//TODO: Add any required headers etc.
apiClient.DoLogin(username,password);
private string GetServiceUrl()
    {
        try
        {
            return
            _configurationRepository.AppSettings[
                _configurationRepository.AppSettings["WebApiInstanceToUse"]];
        }
        catch (NullReferenceException ex)
        {
            //TODO: Log error
            return string.Empty;
        }
    }
<add key="StagingWebApiInstance" value="http://mystagingserver/myProduct/webservices/webapi.asmx "/>
<add key="ProductionWebApiInstance" value="https://www.myurl.com/myProduct/webservices/webapi.asmx"/>
<!-- Identify which WebApi.asmx instance to Use-->
<add key="WebApiInstanceToUse" value="ProductionWebApiInstance"/>