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



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

我有一个web服务(ASP。. NET 4.5)使用一个需要使用会话状态的方法。为了存档这一点,我用EnableSession=true修饰了该方法。这就是MS在这篇文章中建议的做法(见末尾的"代码块A")。

为了使web服务能够重用会话,它需要找到一个具有会话ID的cookie。该cookie在服务器端由web服务器自己在第一次调用该方法时创建和设置。为了在每次调用时重新发送此cookie, MS建议使用分配给web服务代理的"cookie容器",在调用之间保存并在每次调用时重用。(见末尾的"代码块B")。

只要你打算从服务器端调用web服务,这个方法就非常有效。我需要调用它从客户端使用jQuery ajax JSON Post调用(见"代码块C"在结束)。这段代码工作得很好。实际上,带有会话ID的cookie会自动传递给web服务。不需要饼干罐……只要客户端和web服务在同一域中。

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

我在web配置中定义了以下标头,以允许跨域呼叫。

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

那么,缺少什么呢?

代码块A:带有装饰方法的Web Service

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: Server Side Cookie Jar Solution

<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);
                }
            });

经过几个小时的思考和谷歌搜索,我的伴侣发现我们错过了

  • 一个额外的头("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);
    }
});

最新更新