原文:http://blog.csdn.net/kntao/article/details/6921433

 

WCF能够共享ASP.NET的session,不同的WCF客户端代理类在采用Per Call模式下访问WCF能够访问同一个ASP.NET Session.但是WCF的Session和ASP.NET的Session是不同的。

 

  • WCF的Session代表着服务实例,它是被客户端代理类访问时初始化的。WCF依靠消息通道,安全回话和消息模式等来联系session的。
  • 而ASP.NET的session是类似服务端的一种存储数据的模式。它是通过客户端cookie和uri来维护session的

 

1. 利用ASP.NET的session实现认证,在aspx里记录用户认证信息:

 

[csharp] view plaincopyprint?
 
  1. string UserId = HttpContext.Current.User.Identity.Name;   
  2. int Timeout = HttpContext.Current.Session.Timeout  

2. 如果WCF服务端能够共享Asp.NET的session,必须在WCF配置文件中进行如下设置:

 

  1. <serviceHostingEnvironment aspNetCompatibilityEnabled="true"  />  

3.在服务端新建一个用户类:

 

 

[csharp] view plaincopyprint?
 
  1. public static class UserHelper  
  2.    {  
  3.        public  const string SessionUserKey = "Session_Current_User";  
  4.   
  5.        /// <summary>  
  6.        /// 取得当前用户信息  
  7.        /// </summary>  
  8.        public static UserInfo CurrentUser  
  9.        {  
  10.            get  
  11.            {  
  12.                if (!HttpContext.Current.User.Identity.IsAuthenticated)  
  13.                {  
  14.                    HttpContext.Current.Response.Redirect(System.Configuration.ConfigurationManager.AppSettings["LogoutRedirectUrl"]);  
  15.                    return null;  
  16.                }  
  17.   
  18.                string key = SessionUserKey;  
  19.                object user = null;  
  20.   
  21.                if(HttpContext.Current.Session != null)  
  22.                    user = HttpContext.Current.Session[key];  
  23.   
  24.                if (user == null)  
  25.                {  
  26.                    var info = new AdminService().GetUserById(HttpContext.Current.User.Identity.Name); // 获取用户信息  
  27.                    HttpContext.Current.Session[key] = info;  
  28.                    return info;  
  29.                }  
  30.                return (UserInfo)user;  
  31.            }  
  32.            set { HttpContext.Current.Session[SessionUserKey] = value; }  
  33.        }  

4. 在WCF服务端可以利用共享的session来判断权限:

 

 

[csharp] view plaincopyprint?
 
  1. [Serializable]  
  2.     [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]  
  3.     [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]  
  4.     public partial class AdminService : IAdminService  
  5.     {  
  6.         public AdminService()  
  7.         {  
  8.         }  
  9.         public string InsertAdmin(Admin admin)  
  10.         {  
  11.             int errorCount = 0;  
  12.             if (!UserHelper.CurrentUser == null)  
  13.             {  
  14.                 CustomerFaultException exception = new CustomerFaultException  
  15.                 {  
  16.                     ExceptionCode = "S001",  
  17.                     ExceptionMessage = "没有权限访问,请登录!"  
  18.                 };  
  19.                 throw new FaultException<CustomerFaultException>(exception);  
  20.             }  
  21.             AdminSummary adminSummary = adminDal.GetAdminSummary(admin.UserId, out errorCount);  
  22.             if (adminSummary == null)  
  23.                 return adminDal.InsertAdmin(admin);  
  24.             else  
  25.                 return "1001";  
  26.         }  

5.在客户端获取sessionId,我们可以通过Cookie获取客户端的sessionId

 

 

[csharp] view plaincopyprint?
 
  1. void InitialInvoke()  
  2.      {  
  3.          IHelloService proxy = factory.CreateChannel();  
  4.          using (new OperationContextScope((IContextChannel)proxy))  
  5.          {  
  6.              Console.WriteLine(proxy.Greet("Hello"));  
  7.              HttpResponseMessageProperty responseProperty = OperationContext.Current.IncomingMessageProperties[HttpResponseMessageProperty.Name]  
  8.                  as HttpResponseMessageProperty;  
  9.              helper = HttpSessionCookieHelper.Create((string)responseProperty.Headers[HttpResponseHeader.SetCookie]);  
  10.          }  
  11.   
  12.          ((IClientChannel)proxy).Close();  
  13.      }  

httpSessionCookieHelper是从cookie中获取sessionId的(CookieName 是“ASP.NET_SessionId”)

[csharp] view plaincopyprint?
 
  1. class HttpSessionCookieHelper  
  2.        {  
  3.            const string AspNetSessionIdCookieName = "ASP.NET_SessionId";  
  4.            string aspNetSessionId = string.Empty;  
  5.            HttpSessionCookieHelper()  
  6.            { }  
  7.   
  8.            public static HttpSessionCookieHelper Create(string cookieString)  
  9.            {  
  10.                HttpSessionCookieHelper helper = new HttpSessionCookieHelper();  
  11.                helper.ParseCookieString(cookieString);  
  12.                return helper;  
  13.            }  
  14.   
  15.            public static HttpSessionCookieHelper CreateFromSessionId(string sessionId)  
  16.            {  
  17.                HttpSessionCookieHelper helper = new HttpSessionCookieHelper();  
  18.                helper.aspNetSessionId = sessionId;  
  19.                return helper;  
  20.            }  
  21.   
  22.            public void AddSessionIdToRequest(HttpRequestMessageProperty requestProperty)  
  23.            {  
  24.                if (string.IsNullOrEmpty(this.aspNetSessionId))  
  25.                    return;  
  26.   
  27.                string sessionCookieString = string.Format("{0}={1}", AspNetSessionIdCookieName, this.aspNetSessionId);  
  28.                string cookieString = (string)requestProperty.Headers[HttpRequestHeader.Cookie];  
  29.                if (string.IsNullOrEmpty(cookieString))  
  30.                {  
  31.                    cookieString = sessionCookieString;  
  32.                }  
  33.                else  
  34.                {  
  35.                    cookieString = string.Format("{0}; {1}", cookieString, sessionCookieString);  
  36.                }  
  37.   
  38.                requestProperty.Headers[HttpRequestHeader.Cookie] = cookieString;  
  39.            }  
  40.   
  41.            void ParseCookieString(string cookieString)  
  42.            {  
  43.                if (string.IsNullOrEmpty(cookieString))  
  44.                    return;  
  45.   
  46.                string[] cookies = cookieString.Split(';');  
  47.                for (int i = 0; i < cookies.Length; i++)  
  48.                {  
  49.                    string[] cookieNameValues = cookies[i].Split('=');  
  50.                    if (cookieNameValues[0] == AspNetSessionIdCookieName)  
  51.                    {  
  52.                        this.aspNetSessionId = cookieNameValues[1];  
  53.                        return;  
  54.                    }  
  55.                }  
  56.            }  
  57.   
  58.            public string AspNetSessionId  
  59.            {  
  60.                get  
  61.                {  
  62.                    return this.aspNetSessionId;  
  63.                }  
  64.            }  
  65.        }  

这样我们可以在第一次调用的回复中获取sessionId

 

[csharp] view plaincopyprint?
 
  1. void Invoke2()  
  2.       {  
  3.           IHelloService proxy = factory.CreateChannel();  
  4.           using (new OperationContextScope((IContextChannel)proxy))  
  5.           {  
  6.               HttpRequestMessageProperty requestProperty = new HttpRequestMessageProperty();  
  7.               helper.AddSessionIdToRequest(requestProperty);  
  8.               OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProperty;  
  9.               Console.WriteLine(proxy.Greet("Howdy"));  
  10.           }  
  11.   
  12.           ((IClientChannel)proxy).Close();  
  13.   
  14.           if (Interlocked.Increment(ref completedCount) == 2)  
  15.           {  
  16.               waitHandle.Set();  
  17.           }  
  18.       }  

注:第5点可以参照:http://blogs.msdn.com/b/wenlong/archive/2010/02/21/using-asp-net-sessions-from-wcf.aspx