访问.asmx Web服务跨域并将结果加载到级联下拉列表中

时间:2013-06-14 11:11:23

标签: asp.net web-services cross-domain asmx cascadingdropdown

我有2个网站。

我也有网络服务。

当我在级联下拉菜单中加载国家/地区名称时,您可以看到此操作:http://www.mydomain.com/trouwlocaties/zoeken-uitgebreid

但是,同一个Web服务会抛出错误:http://otherdomain.com/weddingvenues/search-advanced 你可以看到下拉列表显示'方法错误-1',在我的Chrome控制台中,我看到:500(内部服务器错误),客户端尝试获取.asmx服务,在toptrouwen上使用POST(就像我一样)相信应该发生什么,也更安全。)

这是GetCountries网络服务:

<System.Web.Script.Services.ScriptService()> _
<System.Web.Services.WebService(Namespace:="http://tempuri.org/")> _
<System.Web.Services.WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
<ToolboxItem(False)> _
Public Class geolocation
'<System.Web.Script.Services.ScriptService()> _
'<WebService(Namespace:="http://tempuri.org/")> _
'<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
'<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _


Inherits System.Web.Services.WebService

<WebMethod()> _
Public Function GetCountries(ByVal knownCategoryValues As String, ByVal category As String) As CascadingDropDownNameValue()
    Dim values As New List(Of CascadingDropDownNameValue)

    Dim myConnection As SqlConnection = GetConnection()
    Dim cmd As New SqlCommand(String.Format("SELECT id,name as title FROM country order by title asc", Threading.Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName), myConnection)
    Try
        myConnection.Open()
        Dim reader As SqlDataReader = cmd.ExecuteReader
        Dim CountryName As String
        Dim CountryID As Integer
        While reader.Read
            CountryName = reader("title").ToString
            Int32.TryParse(reader("id"), CountryID)
            values.Add(New CascadingDropDownNameValue(CountryName, CountryID.ToString))
        End While
    Catch ex As Exception

    Finally
        myConnection.Close()
    End Try

    Return values.ToArray
End Function

End Class   

首先我尝试将其添加到我的web.config:

<system.web>
<webServices>
  <protocols>
    <remove name="Documentation"/>
    <add name="HttpGet"/>
    <add name="HttpPost"/>
  </protocols>
</webServices>
</system.web>

完成此操作后,我在Chrome控制台中收到了此消息:

Uncaught SyntaxError: Unexpected token < 

显然结果不是解释为XML,但我的猜测是JSON。经过一些谷歌搜索后,我认为这与MIME类型有关,但我从未发现如何将此更改为XML服务。

所以我继续搜索并发现其他内容,我正在阅读这些帖子: http://social.msdn.microsoft.com/forums/en-us/asmxandxml/thread/F80BDA62-C87A-4BDA-8CB1-F2CFAD1C8891 Uncaught SyntaxError: Unexpected token < -- in jQuery ajax

显然这可能是一个“跨域问题”。

所以我最终创建了这些文件:

clientaccesspolicy.xml

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
<policy>
  <allow-from http-request-headers="*">
    <domain uri="*"/>
  </allow-from>
  <grant-to>
    <resource path="/" include-subpaths="true"/>
  </grant-to>
</policy>
  </cross-domain-access>
</access-policy>

的crossdomain.xml

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<?xml version="1.0" ?> 
<cross-domain-policy>
    <allow-access-from domain="*" /> 
    <allow-access-from domain="*.otherdomain.com" secure="false" /> 
</cross-domain-policy>

<configuration>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
            <binding name="GetCountries" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"> 
                <security mode="None" />
            </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://www.mydomain.com/geolocation.asmx"
            binding="basicHttpBinding" name="GeoLocation" />
        </client>
    </system.serviceModel>
</configuration> 

在第一个示例链接中,用户还添加了属性bindingConfiguration =“DashboardServiceSoap”和contract =“DashboardService.DashboardServiceSoap”,但我不知道在我的情况下我必须填写什么。

我仍然卡住了,我不知道什么是正确的音轨以及如何配置我的设置。

更新21-06-2013

使用以下内容更新了我的web.config:

<system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name="Access-Control-Allow-Origin" value="*" />
            <add name="Access-Control-Allow-Headers" value="Content-Type" />
      </customHeaders>
    </httpProtocol>

我还尝试了以下4种配置:

<System.Web.Script.Services.ScriptService()> _
<System.Web.Services.WebService(Namespace:="http://tempuri.org/")> _
<System.Web.Services.WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
<ToolboxItem(False)> _
Public Class geolocation

    Inherits System.Web.Services.WebService

场景1和2使用此方法定义:

<WebMethod()> _
Public Function GetCountries(ByVal knownCategoryValues As String, ByVal category As String) As CascadingDropDownNameValue() 

方案1:web.config中的WITH protocols部分

<webServices>
  <protocols>
    <remove name="Documentation"/>
    <add name="HttpGet"/>
    <add name="HttpPost"/>
  </protocols>
</webServices>  

在.nl域上正常工作 在.com域上引发方法错误-1。 Chrome控制台显示:未捕获的SyntaxError:意外的令牌&lt;的getCountries:1

场景2:web.config中没有协议部分

在.nl域上正常工作 在.com域上引发方法错误-1。 Chrome控制台显示:GET http://www.otherdomain.com/geolocation.asmx/GetCountries?knownCategoryValues=%22%22&category=%22Country%22&callback=Sys._jsonp0 500(内部服务器错误)ScriptResource.axd:7773

使用此方法定义的方案3和4:

<WebMethod()> _
<ScriptMethod(UseHttpGet:=True, ResponseFormat:=System.ServiceModel.Web.WebMessageFormat.Json)> _
Public Function GetCountries(ByVal knownCategoryValues As String, ByVal category As String) As CascadingDropDownNameValue() 

方案3:web.config中的WITH protocols部分

<webServices>
  <protocols>
    <remove name="Documentation"/>
    <add name="HttpGet"/>
    <add name="HttpPost"/>
  </protocols>
</webServices>  

在.nl域上引发方法错误500。 Chrome控制台显示:POST http://www.mydomain.com/geolocation.asmx/GetCountries 500(内部服务器错误)catcher.js:197 在下拉列表中的.com域上引发方法错误-1。 Chrome控制台显示:未捕获的SyntaxError:意外的令牌&lt;的getCountries:1

场景4:web.config中没有协议部分                                                     

在.nl域上引发方法错误500。 Chrome控制台显示:无法加载资源:服务器响应状态为500(内部服务器错误) 在下拉列表中的.com域上引发方法错误-1。 Chrome控制台显示:GET http://www.otherdomain.com/geolocation.asmx/GetCountries?knownCategoryValues=%22%22&category=%22Country%22&callback=Sys._jsonp0 500(内部服务器错误)

此外,我并没有明确地从脚本调用.asmx,我让级联下拉列表为我工作。像这样:

<asp:DropDownList ID="ddlCountries" CssClass="textbox" AutoPostBack="true" runat="server"></asp:DropDownList>
<cc1:cascadingdropdown ID="cddCountries" runat="server" Category="Country" Enabled="True" LoadingText="<%$Resources:Glossary,loading %>" PromptText="<%$Resources:Glossary,country_choose %>" 
ServiceMethod="GetCountries" TargetControlID="ddlCountries">
</cc1:cascadingdropdown>

代码隐藏

cddCountries.ServicePath = "http://www.mydomain.com/geolocation.asmx"

我不知道我使用这些预定义元素的事实是否与我的问题有关,我最好自己通过脚本调用.asmx服务并填写下拉列表。如果是这样的话:我不知道该怎么做。

1 个答案:

答案 0 :(得分:1)

你是对的,这是一个跨领域的问题。有几种方法可以解决这个问题:

  1. 只要需要转到Web服务的数据不是很大,您就可以将Web服务转换为JSONP。来自服务的数据可以尽可能大。通过非常大,它必须大约2k字符或更少 - 您可以通过知道它是作为来自脚本标记的src属性的get请求的一部分发送的,在一个JSONP请求中计算可以发送的数据量。

    以下是您可能已经熟悉的JSONP的优秀答案:

    What is JSONP all about?

    更新

    以下是在VB.NET中执行JSONP的示例:

    http://www.sattsoft.com/tutorials/contents/1/14/cross-domain-call-using-ajax-jquery-jsonp-and-vb-net-web-service.html

  2. 您可以创建www.wunderweddings.com的子域名,也可以将其命名为“api.www.wunderweddings.com”并使用DNS将该子域名指向正确的位置,使用A或CNAME记录。然后你会在你的客户端页面中嵌入一个小的(不可见的)iframe,指向这个新的api主机(确保将src指定为“//api.www.underweddings.com”以便匹配http / s包含页面的内容),并使用iframe中的javascript将其document.domain推广到www.wunderweddings.com,你可以通过脚本注入来完成它,但它更容易让服务器上的那个页面提供脚本来完成它,然后您可以在指向您的api的iframe和包含www.wunderweddings.com的iframe的页面之间自由交流。因此,iframe中的代码将为您访问Web服务,获取数据,提升其document.domain,并通知包含页面。

  3. 如果您知道postMessage始终可以在您的客户端上使用(可能不是),您可以在不更改document.domain的情况下执行上述操作。

  4. 上面的第2点和第3点可能听起来很麻烦!特别是如果您打算扩展您提供的Web服务和/或访问该服务的域的数量。如果是这样,我非常强烈建议使用EasyXDM,它是一个非常强大且非常强大的库,用于执行客户端跨域RPC:

    http://easyxdm.net/wp/

    EasyXDM提供postMessage的后备,如果它不可用,例如通过散列或name属性进行通信,以及其他一些内容。

  5. 您可以修复crossdomain.xml。现在这里我有点生疏,但我会给你最好的猜测:

  6. <强>更新

    您希望您的crossdomain.xml像这样:

    <?xml version="1.0" ?> 
    <cross-domain-policy>
        <allow-access-from domain="*" /> 
        <allow-access-from domain="*.wunderweddings.com" /> 
    </cross-domain-policy>
    

    “&lt; cross-domain-policy&gt;”的第一个孩子,即“&lt; allow-access-from domain =”“/&gt;”将使它完全不受限制,而“&lt; allow-access-from domain =” .wunderweddings.com“/&gt;”只有wunderweddings.com和子域才允许浏览器进行跨域调用。您不需要两个“allow-access-from”标记,但至少需要其中一个标记。

    我不确定为什么配置的东西在那里,它不应该。我完全没有注意到第一次,这几乎肯定是你的问题。还要确保从其他服务器(具有Web服务的服务器)提供crossdomain.xml。

    所以只是为了澄清一下,crossdomain.xml不应该在底部有额外的XML,&lt; onfiguration&gt; ...&lt; / configuration&gt;标签及其中的所有内容,所有这些都是从某个地方泄漏而不应该在crossdomain.xml内部


    最终更新

    对于那些有类似问题的人来说,Floran发现了无效字符的问题:

    这必须添加到页面顶部:

    <asp:ScriptManagerProxy ID="ScriptManagerProxy1" runat="server"> 
    <Services> 
    <asp:ServiceReference Path="geolocation.asmx" /> 
    </Services> 
    </asp:ScriptManagerProxy>