こんばんは。

今夜は Azure のセッションについて調べてみた。
調べていて、良いまとめサイトがあったので紹介します。

ブチザッキ - {2011/08/23}   Windows AzureのWeb Roleでセッションを共有する
http://buchizo.wordpress.com/2011/08/23/windows-azure%E3%81%AEweb-role%E3%81%A7%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E5%85%B1%E6%9C%89%E3%81%99%E3%82%8B/

では今夜はこのへんで…

 

ごめんなさい。

以上の記事に書かれていることで、だいたいのセッションの問題は解決すると思いうけど、
あるものを使うだけでは面白くないため、今回から自前でセッション管理してみようとおもいます。

まず、簡単なカスタムセッションを作ってみます。
SessionStateStoreProviderBase クラスを継承して作っていくようです。
http://msdn.microsoft.com/ja-jp/library/ms178587%28v=VS.90%29.aspx

サンプルはMSDNにもあるのでそれをみつつ…
http://msdn.microsoft.com/ja-jp/library/ms178588%28v=VS.90%29.aspx
http://msdn.microsoft.com/ja-jp/library/ms178589%28v=VS.90%29.aspx

public class TestSessionStateProvider : System.Web.SessionState.SessionStateStoreProviderBase {

        private int Timeout {
            get { return 20; }
        }

        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) {
            base.Initialize(name, config);
        }
        public override void InitializeRequest(HttpContext context) {
        }

        public override void EndRequest(HttpContext context) {
        }

        public override void Dispose() {
        }

        public override System.Web.SessionState.SessionStateStoreData GetItemExclusive(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out System.Web.SessionState.SessionStateActions actions) {
            return GetSessionData(true, context, id, out locked, out lockAge, out lockId, out actions);
        }

        public override System.Web.SessionState.SessionStateStoreData GetItem(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out System.Web.SessionState.SessionStateActions actions) {
           return GetSessionData(false, context, id, out locked, out lockAge, out lockId, out actions);
        }

        public override void SetAndReleaseItemExclusive(HttpContext context, string id, System.Web.SessionState.SessionStateStoreData item, object lockId, bool newItem) {
            UpdateSessionData(context, id, item, lockId, newItem);
        }

        public override void ReleaseItemExclusive(HttpContext context, string id, object lockId) {
            // 実装は後ほど
        }

        public override void RemoveItem(HttpContext context, string id, object lockId, System.Web.SessionState.SessionStateStoreData item) {
            // 実装は後ほど
        }

        public override void CreateUninitializedItem(HttpContext context, string id, int timeout) {
            // 実装は後ほど
        }

        public override System.Web.SessionState.SessionStateStoreData CreateNewStoreData(HttpContext context, int timeout) {
            return new SessionStateStoreData(new SessionStateItemCollection(),
                                             SessionStateUtility.GetSessionStaticObjects(context),
                                             timeout);
        }

        public override bool SetItemExpireCallback(System.Web.SessionState.SessionStateItemExpireCallback expireCallback) {
            // 実装は後ほど
            return false;
        }

        public override void ResetItemTimeout(HttpContext context, string id) {
            // 実装は後ほど
        }

        private SessionStateStoreData GetSessionData(bool lockSession, HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out System.Web.SessionState.SessionStateActions actions) {
            // 今回は、HttpContext.Application にセッション情報を保存する

            SessionStateStoreData sessionState;

            Dictionary<string, byte[]> sessionData
                = (Dictionary<string, byte[]>)HttpContext.Current.Application["session"];

            // id のセッションがあるか
            if ( sessionData != null && sessionData.ContainsKey(id) ) {
                // セッションを復元

                using ( var stream = new MemoryStream(sessionData[id]) ) {
                    using ( var reader = new BinaryReader(stream) ) {

                        sessionState = new SessionStateStoreData(SessionStateItemCollection.Deserialize(reader),
                                                         SessionStateUtility.GetSessionStaticObjects(context),
                                                         this.Timeout);
                    }
                }

            } else {
                // 新規にセッションを作成
                sessionState = CreateNewStoreData(context, this.Timeout);
            }
           
            locked = false;
            lockId = null;
            lockAge = new TimeSpan(0, this.Timeout, 0);
            actions = SessionStateActions.None;

            return sessionState;
        }

        private void UpdateSessionData(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem) {
            // HttpContext.Application に保存されているセッション情報を復元する

            Dictionary<string, byte[]> sessionData
                = (Dictionary<string, byte[]>)HttpContext.Current.Application["session"];
            if ( sessionData == null ) {
                sessionData = new Dictionary<string, byte[]>();
            }

            using ( var stream = new MemoryStream() ) {
                using ( var writer = new BinaryWriter(stream) ) {
                    var sessionItem = (SessionStateItemCollection)item.Items;
                    sessionItem.Serialize(writer);
                }

                sessionData[id] = stream.GetBuffer();
            }

            HttpContext.Current.Application["session"] = sessionData;
        }

    }

ただ HttpContext.Application に保存するだけのものです。
(InProc セッションの超劣化版)

これから少しずつまともに使えるものにしていこう。