如何使启用会话的 ASP.NET Web 服务与不同域中的 ajax 客户端一起工作?

Posted

技术标签:

【中文标题】如何使启用会话的 ASP.NET Web 服务与不同域中的 ajax 客户端一起工作?【英文标题】:How to make a session enabled ASP.NET web service work with an ajax client in a different domain? 【发布时间】:2014-09-02 15:30:37 【问题描述】:

我和我的同事花了很多时间寻找这个答案,所以我想我应该分享这个自我回答的问题。

我有一个 Web 服务 (ASP.NET 4.5),其方法需要使用会话状态。为了存档这个,我用 EnableSession=true 修饰了这个方法。这是 MS 在this article 中建议做的事情(见最后的“代码块 A”)。

为了让网络服务能够重新使用会话,它需要找到一个带有会话 ID 的 cookie。该 cookie 在服务器端由 Web 服务器本身在第一次调用该方法时创建和设置。为了在每次调用时重新发送此 cookie,MS 建议使用分配给 Web 服务代理的“cookie 容器”,在调用之间保存并在每次调用时重复使用。 (见最后的“代码块 B”)。

只要您打算从服务器端调用 Web 服务,这非常有效。我需要使用 jQuery ajax JSON Post 调用从客户端调用它(参见最后的“代码块 C”)。这段代码很好用。事实上,带有会话 ID 的 cookie 会自动传递给 Web 服务。不需要cookie jar...只要客户端和Web 服务在同一个域中。

如果客户端位于与 Web 服务 (domainb.com) 不同的域 (domaina.com) 中,则根本不会传递带有会话 ID 的 cookie。因此,对 Web 服务的每次调用都被视为第一次调用。

我在网络配置中定义了以下标头以允许跨域调用。

<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />

那么,缺少什么?

代码块 A:带有修饰方法的 Web 服务

public class Util: WebService 
    [ WebMethod(EnableSession=true)]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
    public int SessionHitCounter() 
       if (Session["HitCounter"] == null) 
          Session["HitCounter"] = 1;
       
       else 
          Session["HitCounter"] = ((int) Session["HitCounter"]) + 1;
          
       return ((int) Session["HitCounter"]);
       
 

代码块 B:服务器端 Cookie Jar 解决方案

<script runat="server">

    void EnterBtn_Click(Object Src, EventArgs E) 

  // Create a new instance of a proxy class for your XML Web service.
  ServerUsage su = new ServerUsage();
      CookieContainer cookieJar;

  // Check to see if the cookies have already been saved for this session.
  if (Session["CookieJar"] == null) 
    cookieJar= new CookieContainer();
      else
   cookieJar = (CookieContainer) Session["CookieJar"];

    // Assign the CookieContainer to the proxy class.
    su.CookieContainer = cookieJar;

  // Invoke an XML Web service method that uses session state and thus cookies.
  int count = su.PerSessionServiceUsage();         

  // Store the cookies received in the session state for future retrieval by this session.
  Session["CookieJar"] = cookieJar;

      // Populate the text box with the results from the call to the XML Web service method.
      SessionCount.Text = count.ToString();  
    

</script>

代码块 C:Ajax 调用

            $.ajax(
                type: "POST",
                url: web_services_url + "/SessionHitCounter",
                data: "",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (msg) 
                    alert(msg.d);
                
            );

【问题讨论】:

【参考方案1】:

经过数小时的思考和谷歌搜索我的伴侣发现我们失踪了

一个额外的标头(“Access-Control-Allow-Credentials”) 将“Access-Control-Allow-Origin”上的“*”更改为调用 Web 服务的特定域 在 ajax 调用中添加额外参数 (withCredentials)

这些是启用 CORS 所需的标头

<add name="Access-Control-Allow-Origin" value="http://localhost:53710" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Credentials" value="true" />

这是带有额外参数的ajax调用

$.ajax(
    type: "POST",
    xhrFields:  withCredentials: true ,
    url: web_services_url + "/SessionHitCounter",
    data: "",
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function (msg) 
        alert(msg.d);
    
);

【讨论】:

以上是关于如何使启用会话的 ASP.NET Web 服务与不同域中的 ajax 客户端一起工作?的主要内容,如果未能解决你的问题,请参考以下文章

电话间隙 HTML 应用程序可以与 asp.net Mvc Web 服务器建立会话吗

如何使 ASP.NET Web API Web 服务在本地网络中可用

启用 ASP.Net Core 会话锁定?

ASP.NET MVC:如何防止会话锁定?

如何在 ASP.Net Web API 中为特定控制器启用 Windows 身份验证

使用 ASP.NET 会话状态服务跨应用程序共享会话