2012-10-29 19 views
8

मैं SQL सर्वर सत्र स्थिति का एक बहुत ही मूल डेमो स्थापित कर रहा हूं, लेकिन मुझे इसे काम करने में कुछ परेशानी हो रही है। मैं इसे आईआईएस 7.5 और एसक्यूएल सर्वर 2008 आर 2 के साथ स्थानीय रूप से विंडोज 7 चलाने का परीक्षण करने की कोशिश कर रहा हूं।वेब अनुप्रयोगों में SQL सर्वर सत्र राज्य साझा करना

आखिरकार, मुझे कुछ अलग-अलग वेब सर्वरों के बीच लोड-संतुलित सिस्टम में लॉग इन किए गए उपयोगकर्ताओं की संख्या को ट्रैक करने का एक तरीका चाहिए। तो जब भी कोई उपयोगकर्ता लॉग इन करता है या बाहर करता है तो मुझे एक सत्र चर (एसक्यूएल में संग्रहीत) को अपडेट करने की आवश्यकता होती है। इसलिए सत्र आईडी हमेशा अलग हो सकती है। क्या यह संभव है?

यहाँ मैं अब तक क्या किया है:

    आईआईएस (site1 और Site2) में
  1. निर्मित दो नई साइटें
  2. वी.एस. 2010 (site1 और Site2) में दो नए वेब अनुप्रयोग प्रोजेक्ट बनाए गए
  3. दोनों साइटों में, Default.aspx पृष्ठ पर, मैंने एक बटन बनाया है जिसे क्लिक करने पर "साइट 1" या "साइट 2" (साइट पर निर्भर करता है) को "LastSiteUsed" नामक सत्र चर में सहेजा जाएगा। एक और बटन है, जिसे क्लिक करने पर, "LastSiteUsed" सत्र चर से मान पढ़ेगा और इसे लेबल में प्रदर्शित करेगा।
  4. एसक्यूएल में, मैंने dbSessionTest नामक एक नया डेटाबेस बनाया है। फिर मैंने MSDN to install the Session State Database using the aspnet_regsql tool पर निर्देशों का पालन किया।
  5. मेरी वेब अनुप्रयोग के Web.config फ़ाइल के दोनों में, मैं निम्नलिखित जोड़ दिया है <System.Web> के तहत:

<sessionState mode="SQLServer" sqlConnectionString="server=.\sqlexpress;database=dbSessionTest;uid=myUsername;pwd=myPassword" cookieless="false" timeout="20" allowCustomSqlDatabase="true"/>

दोनों साइटों सामान्य रूप से कार्य है, लेकिन वे साझा करने होने लगते नहीं है अधिवेशन। उदाहरण के लिए, जब मैं साइट 1 से अपना सत्र चर सहेजने के लिए अपने बटन पर क्लिक करता हूं, तो मैं साइट 2 से उस मान को पढ़ने में सक्षम होने की उम्मीद करता हूं, लेकिन यह काम नहीं करता है। साइट 2 केवल "साइट 2" लौटाएगा और साइट 1 केवल "साइट 1" लौटाएगा।

क्या किसी के पास कोई विचार है कि मैं क्या गलत कर सकता हूं? क्या मैं यह सोचने में गलत हूं कि मुझे साइट 2 से साइट 1 द्वारा एक मूल्य सेट पढ़ने में सक्षम होना चाहिए?

अद्यतन:

मुझे लगता है कि सत्र डेटा एसक्यूएल प्रबंधन स्टूडियो में ASPStateTempSessions तालिका में संग्रहीत किया जा रहा है देख सकते हैं, लेकिन हर साइट अभी भी केवल मूल्य जो लिखा था देख सकते हैं। दोनों साइटों को इस तरह सत्र चर सेट कर रहे हैं:

Session("LastSiteUsed") = "Site2" 

और दोनों साइटों की तरह मूल्य को पुन: प्राप्त कर रहे हैं:

lblValue.Text = "Value from Session: " & Session("LastSiteUsed").ToString 

मैं एसक्यूएल सर्वर में संग्रहीत सत्र चर तक पहुँचने के लिए अलग तरह से ऐसा करने की जरूरत है?

अद्यतन 2:

मैं डिफ़ॉल्ट डेटाबेस, ASPState है, जो इस आदेश चलाकर बनाई गई है का उपयोग कर की कोशिश की है:

aspnet_regsql.exe -S MyServerName -E -ssadd -sstype p 

तब मेरे वेब से प्रत्येक को सरल बनाया।config फ़ाइलों की तरह:

<sessionState mode="SQLServer" sqlConnectionString="Data Source=.\sqlexpress;User ID=myUsername;Password=myPassword" cookieless="false" timeout="20"/> 

लेकिन फिर से, कोई भाग्य। मैं साइट 1 से सत्र चर सेट करने में सक्षम होना चाहता हूं और फिर साइट 2 से मान पढ़ सकता हूं, लेकिन यह काम नहीं कर रहा है। दोबारा, मैं ASPStateTempSessions तालिका में दिखाए गए प्रविष्टियों को देख पा रहा हूं, इसलिए मुझे पता है कि वे सही तरीके से दर्ज हो रहे हैं। एक बात मैंने देखी है कि उनके पास अलग-अलग सत्र आईडी हैं?

क्या ऐसा कुछ है जो मुझे अलग-अलग करने की ज़रूरत है ताकि यह सुनिश्चित किया जा सके कि उसी सत्र आईडी को सेट/पढ़ने के दौरान मेरी साइट के बीच एक ही सत्र आईडी का उपयोग किया जाए?

अद्यतन 3:

मैं से this article जो एक सपा को संशोधित करता है और ASPStateTempApplications मेज पर समूहीकरण के लिए कॉलम जोड़ने पर निर्देशों का पालन किया। यह की तरह काम किया, लेकिन केवल तभी जब मेरी दोनों साइटें एक ही ब्राउज़र में खुली थीं (टैब का उपयोग करके)। मुझे आईई में साइट 1 खोलने, मेरे सत्र चर के लिए एक मूल्य सहेजने, ब्राउज़र को बंद करने, क्रोम में साइट 2 खोलने और मूल्य पढ़ने में सक्षम होना चाहिए। एसक्यूएल सर्वर सत्र राज्य के साथ मैंने जो कुछ भी पढ़ा है, उससे यह संभव होना चाहिए।

अद्यतन 4 - समाधान:

मैं @SilverNinja द्वारा प्रदान की this article पर जवाब का पालन किया। मैंने कमांड प्रॉम्प्ट के माध्यम से ASPState डेटाबेस को फिर से बनाया (अपडेट # 3 में मेरे एसपी परिवर्तन पूर्ववत करने के लिए) और फिर लिंक से उत्तर के अनुसार TempGetAppID एसपी संशोधित किया। मैं भी उस लेख से जवाब के रूप में अच्छी तरह से मिलान करने के लिए मेरी Web.config फ़ाइलों के दोनों को नवीनीकृत किया है:

<machineKey validationKey="59C42C5AB0988049AB0555E3F2128061AE9B75E3A522F25B34A21A46B51F188A5C0C1C74F918DFB44C33406B6E874A54167DFA06AC3BE1C3FEE8506E710015DB" decryptionKey="3C98C7E33D6BC8A8C4B7D966F42F2818D33AAB84A81C594AF8F4A533ADB23B97" validation="SHA1" decryption="AES" /> 
:

<sessionState mode="SQLServer" 
       sqlConnectionString="Data Source=.\sqlexpress;User ID=myUsername;Password=myPassword;Application Name=CacheTest"/> 

मैं भी दोनों Web.config फ़ाइलों में समान मशीन कुंजी को शामिल किया है

अब मैं अपनी दोनों साइटों को खोलने के लिए (आईई का उपयोग कर) सक्षम हूं, साइट 1 से एक मूल्य निर्धारित करता हूं, और इसे साइट 2 (और इसके विपरीत) से पढ़ता हूं। जब मैं तालिका की जांच करता हूं, केवल एक सत्र आईडी मौजूद है (दोनों साइटें एक ही सत्र का सही ढंग से उपयोग कर रही हैं)। एक नया ब्राउज़र खोलने से पहले मैं अपनी सोच में गलत था (उदाहरण के लिए, क्रोम के साथ), उसी सत्र का उपयोग करेगा - एक नया ब्राउज़र इसका अपना सत्र शुरू करेगा। हालांकि लोड-संतुलित परिदृश्य पर, इससे कोई समस्या नहीं होनी चाहिए।

+0

'एप्लिकेशन नाम = कैशटेस्ट' सभी वेब एप्लिकेशन (वेबसाइट्स) के लिए समान है? या ** अलग-अलग मूल्य **? – Kiquenet

उत्तर

7

आपके पास समस्या एएसपी.NET अनुप्रयोगों में साझा सत्र स्थिति है। यह SQL सर्वर सत्र प्रदाता के साथ आउट-ऑफ-द-बॉक्स समर्थित नहीं है। यह SO post regarding what changes to make to SQL Server session provider to support cross-application sessions देखें।

मैं इस साझा स्थिति (यानी LastSiteUsed) के प्रबंधन के लिए सत्र का उपयोग नहीं करता। यह जानकारी उपयोगकर्ता प्रोफ़ाइल स्टोर (Membership, Profile provider, कस्टम डीबी, आदि) के साथ जारी रहनी चाहिए। चूंकि सत्र समाप्त हो सकता है - अनुप्रयोगों में साझा सत्र का उपयोग लगातार उपयोगकर्ता-विशिष्ट स्थिति को ट्रैक करने के लिए एक विश्वसनीय तंत्र नहीं है। यदि इन-मेमोरी क्रॉस-एप्लिकेशन साझा स्थिति के लिए AppFabric Cache का उपयोग करने से दृढ़ता महत्वपूर्ण नहीं है।

+0

उत्तर के लिए धन्यवाद! मुझे लगता है कि यदि सत्र समाप्त हो जाता है तो यह ठीक होना चाहिए (अगर मैं सही ढंग से समझ रहा हूं) क्योंकि मैं आखिरकार लॉग इन समवर्ती उपयोगकर्ताओं की संख्या को ट्रैक कर रहा हूं। ऐसा कहा जा रहा है, क्या आपका पहला लिंक जो मुझे चाहिए उसे पूरा करने के लिए पर्याप्त होगा (विशेष रूप से उस लिंक का जवाब)? – lhan

+0

एफडब्ल्यूआईडब्ल्यू मैं आगे बढ़ गया और उस समाधान की कोशिश की, लेकिन यह काम नहीं किया। इसके बारे में थोड़ा और सोचकर, यह स्थिति अलग है। वे एक ही सर्वर पर एक सत्र साझा करना चाहते थे। मुझे SQL में संग्रहीत एकाधिक लोड संतुलित सर्वरों के बीच एक सत्र चर साझा करने की आवश्यकता है। ऐसा लगता है कि यह संभव होना चाहिए? – lhan

+0

यदि सर्वर लोड-संतुलित हैं - आपको बस यह सुनिश्चित करने की आवश्यकता है कि साझा सत्र तक पहुंचने वाले एप्लिकेशन के लिए उनके पास ''machine.config' या' machine.config' में ** एक ही मशीन कुंजी ** है। चाहे वह वही सर्वर या अलग-अलग सर्वर हो - इससे कोई फर्क नहीं पड़ता कि चाबियाँ समान हैं। – SliverNinja

2

किसी भी व्यक्ति जो डेटाबेस की संग्रहीत प्रक्रियाओं को संशोधित किए बिना इस समस्या को हल करने या हल करने की आवश्यकता है, इस दृष्टिकोण पर विचार करें (बेहोश दिल के लिए नहीं)।

मूल विचार यह है कि SqlSessionStateStore.SqlPartitionInfo का एक स्थिर उदाहरण System.Web.SessionState.SqlSessionStateStore.s_singlePartitionInfo में संग्रहीत है जिसे मैं InitSqlInfo पर कॉल करके प्रारंभ करता हूं। एक बार यह इंस्टेंस प्रारंभ हो जाने के बाद, मैंने आंतरिक _appSuffix फ़ील्ड का मान सेट किया। उदाहरण को _appSuffix फ़ील्ड सेट करने से पहले आरंभ करने की आवश्यकता है, अन्यथा प्रारंभिकरण के दौरान मेरा कस्टम मान ओवरराइट किया जाएगा। मैं एएसपी.NET राज्य डेटाबेस में उसी हैश फ़ंक्शन का उपयोग करके प्रदान किए गए एप्लिकेशन नाम से हैश कोड की गणना करता हूं।

ध्यान दें कि यह जितना बुरा हो जाता है, और यह आंतरिक कार्यान्वयन विवरणों पर पूरी तरह से निर्भर है जो किसी भी समय बदल सकता है। हालांकि, मुझे किसी भी व्यावहारिक विकल्प के बारे में पता नहीं है। अपने विवेकाधिकार और जोखिम पर प्रयोग करें।

अब जब मैंने अपना अस्वीकरण दिया है, तो मुझे आश्चर्य होगा कि .NET बीसीएल में यह कार्यान्वयन बदल गया है क्योंकि प्रमाणीकरण के इस दृष्टिकोण को प्रतिस्थापित किया जा रहा है और मुझे माइक्रोसॉफ्ट के लिए वहां पर टंकण करने का कोई कारण नहीं दिख रहा है।

/* 
* This code is a workaround for the fact that session state in ASP.NET SqlServer mode is isolated by application. The AppDomain's appId is used to 
* segregate applications, and there is no official way exposed to modify this behaviour. 
* 
* Some workarounds tackle the problem by modifying the ASP.NET state database. This workaround approaches the problem from the application code 
* and will be appropriate for those who do not want to alter the database. We are using it during a migration process from old to new technology stacks, 
* where we want the transition between the two sites to be seamless. 
* 
* As always, when relying on implementation details, the reflection based approach used here may break in future/past versions of the .NET framework. 
* Test thoroughly. 
* 
* Usage: add this to your Global.asax: 
*  protected void Application_BeginRequest() 
*  { 
*   SessionStateCrossApplicationHacker.SetSessionStateApplicationName("an application"); 
*  } 
*/ 

using System; 
using System.Data.SqlClient; 
using System.Globalization; 
using System.Reflection; 
using System.Web.SessionState; 

public static class SessionStateCrossApplicationHacker 
{ 
    static string _appName; 
    static readonly object _appNameLock = new object(); 

    public static void SetSessionStateApplicationName(string appName) 
    { 
     if (_appName != appName) 
     { 
      lock (_appNameLock) 
      { 
       if (_appName != appName) 
       { 
        SetSessionStateApplicationNameOnceOnly(appName); 

        _appName = appName; 
       } 
      } 
     } 
    } 

    static void SetSessionStateApplicationNameOnceOnly(string appName) 
    { 
     //get the static instance of SqlSessionStateStore.SqlPartitionInfo from System.Web.SessionState.SqlSessionStateStore.s_singlePartitionInfo 
     var sqlSessionStateStoreType = typeof (SessionStateMode).Assembly.GetType("System.Web.SessionState.SqlSessionStateStore"); 
     var sqlSessionStatePartitionInfoInstance = GetStaticFieldValue(sqlSessionStateStoreType, "s_singlePartitionInfo"); 
     if (sqlSessionStatePartitionInfoInstance == null) 
      throw new InvalidOperationException("You'll need to call this method later in the pipeline - the session state mechanism (SessionStateModule, which is an IHttpModule) has not been initialised yet. Try calling this method in Global.asax's Application_BeginRequest. Also make sure that you do not specify a partitionResolverType in your web.config."); 

     //ensure that the session has not been used prior to this with an incorrect app ID 
     var isStaticSqlPartitionInfoInitialised = GetFieldValue<bool>(sqlSessionStatePartitionInfoInstance, "_sqlInfoInited"); 
     if (isStaticSqlPartitionInfoInitialised) 
      throw new InvalidOperationException("You'll need to call this method earlier in the pipeline - before any sessions have been loaded."); 

     //force initialisation of the static SqlSessionStateStore.SqlPartitionInfo instance - otherwise this will happen later and overwrite our change 
     var connectionString = GetFieldValue<string>(sqlSessionStatePartitionInfoInstance, "_sqlConnectionString"); 
     using (var connection = new SqlConnection(connectionString)) 
     { 
      connection.Open(); 
      CallInstanceMethod(sqlSessionStatePartitionInfoInstance, "InitSqlInfo", connection); 
     } 

     //calculate and set the application hash code 
     string applicationNameHashCode = GetHashCode(appName).ToString("x8", CultureInfo.InvariantCulture); 
     GetField(sqlSessionStatePartitionInfoInstance, "_appSuffix").SetValue(sqlSessionStatePartitionInfoInstance, applicationNameHashCode); 
    } 

    static int GetHashCode(string appName) 
    { 
     string s = appName.ToLower(); 
     int hash = 5381; 
     int len = s.Length; 

     for (int i = 0; i < len; i++) 
     { 
      int c = Convert.ToInt32(s[i]); 
      hash = ((hash << 5) + hash)^c; 
     } 

     return hash; 
    } 

    static void CallInstanceMethod(object instance, string methodName, params object[] parameters) 
    { 
     var methodInfo = instance.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance); 
     methodInfo.Invoke(instance, parameters); 
    } 

    static object GetStaticFieldValue(Type typeWithStaticField, string staticFieldName) 
    { 
     return typeWithStaticField.GetField(staticFieldName, BindingFlags.NonPublic | BindingFlags.Static).GetValue(null); 
    } 

    static FieldInfo GetField(object instance, string name) 
    { 
     return instance.GetType().GetField(name, BindingFlags.NonPublic | BindingFlags.Instance); 
    } 

    static T GetFieldValue<T>(object instance, string name) 
    { 
     return (T)GetField(instance, name).GetValue(instance); 
    } 
} 
+0

प्रत्येक ** वेब एप्लिकेशन ** का अपना *** एपनाम *** है? – Kiquenet

संबंधित मुद्दे