0

У меня проблемы с кодом управления файлом cookie. На каждой странице я смотрю, установлено ли значение ключа. Моя проблема в том, что просмотр файла cookie создает пустой файл cookie.HttpCookie работает локально, но не на сервере

Локально, я могу посмотреть на файл cookie, а затем установить значение ключа, и все в порядке с миром. Но когда я переношу свой код на тестовый сервер, все ведет себя по-другому. Для одного, локально, выдается только один cookie (показано в хром-инструментах). На сервере выдается 2 файла cookie с тем же кодом.

Я написал этот код около 4 лет назад, и он был разработан для .net 2.0, когда поведение HttpCookie было изменено, так что просмотр cookie создавал пустой, если он не существовал. Раньше в .Net 1.1 возвращался null. Теперь мне интересно, что что-то фундаментальное изменилось между 2.0 и 4.0.

Я должен отметить, что мой локальный компьютер - это Windows 7, а сервер - это сервер Windows 2003, но это не должно иметь никакого значения. Единственное, что нужно отметить, это то, что приложение работает в виртуальном каталоге на сервере. Может ли это сыграть роль в проблемах? Я не уверен. Я попытался установить путь к файлу cookie на путь виртуального каталога без везения.

My cookie имеет несколько уровней, включая базовый уровень для непосредственного взаимодействия с http cookie, уровень шифрования, который можно включить или отключить для отладки, а затем уровень управления. Я собираюсь поделиться своим кодом в надежде, что у меня есть вопиющая ошибка в моей логике.

Я также хочу упомянуть, что я использую cookie FormsAuthentication для чего-то другого. Этот файл cookie предназначен для некоторых посторонних, но требуемых данных.

Мой базовый слой печенья:

public abstract class BaseCookie 
{ 
    #region Private Variables 
    private string cookieName; 
    private int timeout = 30; 
    private ExpirationMode expirationMode = ExpirationMode.SlidingExpiration; 
    private string domain; 
    private bool httpOnly = true; 
    private string path = "/"; 
    private bool secure; 
    private string cookieValue; 
    #endregion 

    #region Public Properties 

    /// <summary> 
    /// The name of the cookie as it appears in the request and response 
    /// </summary> 
    protected string CookieName 
    { 
     get { return cookieName; } 
     set { cookieName = value; } 
    } 

    /// <summary> 
    /// The expiration mode of the cookie (default SlidingExpiration) 
    /// </summary> 
    public ExpirationMode ExpirationMode 
    { 
     get { return expirationMode; } 
    } 

    /// <summary> 
    /// The timeout in minutes (default 30) 
    /// </summary> 
    public int Timeout 
    { 
     get { return timeout; } 
     set { timeout = value; } 
    } 

    /// <summary> 
    /// The cookie domain (default String.Empty) 
    /// </summary> 
    public string Domain 
    { 
     get { return domain; } 
     set { domain = value; } 
    } 

    /// <summary> 
    /// Whether or not the cookie is http only (default true) 
    /// </summary> 
    public bool HttpOnly 
    { 
     get { return httpOnly; } 
     set { httpOnly = value; } 
    } 

    /// <summary> 
    /// The path of the cookie (default "/") 
    /// </summary> 
    public string Path 
    { 
     get { return path; } 
     set { path = value; } 
    } 

    /// <summary> 
    /// Whether or not the cookie supports https (default false) 
    /// </summary> 
    public bool Secure 
    { 
     get { return secure; } 
     set { secure = value; } 
    } 

    /// <summary> 
    /// The Value of the cookie (NOTE: this should only be used for setting the value when calling AppendNewCookie(). 
    /// This will not change the value of the cookie after initialization. Use SetCookieValue and GetCookieValue after initialization. 
    /// </summary> 
    public string Value 
    { 
     get { return cookieValue; } 
     set { cookieValue = value; } 
    } 

    /// <summary> 
    /// The cookie in the Request 
    /// </summary> 
    private HttpCookie RequestCookie 
    { 
     get 
     { 
      return HttpContext.Current.Request.Cookies.Get(CookieName); 
     } 
    } 

    /// <summary> 
    /// The cookie in the Response 
    /// </summary> 
    private HttpCookie ResponseCookie 
    { 
     get 
     { 
      return HttpContext.Current.Response.Cookies.Get(CookieName); 
     } 
    } 

    #endregion 

    #region Constructors 
    /// <summary> 
    /// Constructor setting the name of the cookie with Sliding Expiration 
    /// </summary> 
    /// <param name="cookieName">the name of the cookie</param> 
    public BaseCookie(string cookieName) 
     : this(cookieName, ExpirationMode.SlidingExpiration) 
    { 

    } 

    /// <summary> 
    /// Constructor setting the name of the cookie and the expiration mode 
    /// </summary> 
    /// <param name="cookieName">the name of the cookie</param> 
    /// <param name="expirationMode">the Olympus.Cookies.ExpirationMode of the cookie</param> 
    public BaseCookie(string cookieName, ExpirationMode expirationMode) 
    { 
     this.cookieName = cookieName; 

     CookieConfig config = Configuration.CookieConfiguration.Cookies[cookieName]; 

     if (config != null) 
     { 
      Domain = config.Domain; 
      HttpOnly = config.HttpOnly; 
      Path = config.Path; 
      Secure = config.Secure; 
      Timeout = config.Timeout; 
     } 

     //EnsureCookie(); 
    } 
    #endregion 

    /// <summary> 
    /// This method ensures that the cookie is not empty if it exists in either the request or response. 
    /// Due to changes in the cookie model for 2.0, this step is VITAL to cookie management. 
    /// </summary> 
    protected void EnsureCookie() 
    { 
     //if the cookie doesn't exist in the response (hasn't been altered or set yet this postback) 
     if (IsNull(ResponseCookie)) 
     { 
      //if the cookie exists in the request 
      if (!IsNull(RequestCookie)) 
      { 
       //get the cookie from the request 
       HttpCookie cookie = RequestCookie; 

       //update the expiration 
       if (ExpirationMode == ExpirationMode.NoExpiration) 
       { 
        cookie.Expires = DateTime.Now.AddYears(10); 
       } 
       else 
       { 
        cookie.Expires = DateTime.Now.AddMinutes(Timeout); 
       } 

       //set the cookie into the response 
       HttpContext.Current.Response.Cookies.Set(cookie); 
      } 
      else 
      { 
       //if the response and request cookies are null, append a new cookie 
       AppendNewCookie(); 
      } 
     } 
    } 

    /// <summary> 
    /// Append an empty cookie to the Response 
    /// </summary> 
    public virtual void AppendNewCookie() 
    { 
     HttpCookie cookie = new HttpCookie(CookieName); 

     cookie.Domain = Domain; 
     cookie.HttpOnly = HttpOnly; 
     cookie.Path = Path; 
     cookie.Secure = Secure; 

     cookie.Value = Value; 

     if (ExpirationMode == ExpirationMode.NoExpiration) 
     { 
      cookie.Expires = DateTime.Now.AddYears(10); 
     } 
     else 
     { 
      cookie.Expires = DateTime.Now.AddMinutes(Timeout); 
     } 

     HttpContext.Current.Response.Cookies.Add(cookie); 
    } 

    /// <summary> 
    /// Determine if the Cookie is null. 
    /// </summary> 
    /// <remarks> 
    /// Due to changes in the 2.0 cookie model, looking in the request or respnse creates an empty cookie with an 
    /// expiration date of DateTime.MinValue. Previously, a null value was returned. This code calls one of these 
    /// empty cookies a null cookie. 
    /// </remarks> 
    /// <param name="cookie">the cookie to test</param> 
    /// <returns>System.Boolean true if the cookie is "null"</returns> 
    protected static bool IsNull(HttpCookie cookie) 
    { 
     if (cookie == null) 
     { 
      return true; 
     } 
     else 
     { 
      if (String.IsNullOrEmpty(cookie.Value) && cookie.Expires == DateTime.MinValue) 
      { 
       return true; 
      } 
     } 

     return false; 
    } 

    /// <summary> 
    /// Update the expiration of the response cookie 
    /// <remarks> 
    /// If this is not done, the cookie will never expire because it will be updated with an expiry of DateTime.Min 
    /// </remarks> 
    /// </summary> 
    protected void SetExpiration() 
    { 
     if (ExpirationMode == ExpirationMode.NoExpiration) 
     { 
      ResponseCookie.Expires = DateTime.Now.AddYears(10); 
     } 
     else 
     { 
      ResponseCookie.Expires = DateTime.Now.AddMinutes(Timeout); 
     } 
    } 

    /// <summary> 
    /// Set the value of a cookie. 
    /// </summary> 
    /// <remarks> 
    /// Setting value will override all attributes. 
    /// </remarks> 
    /// <param name="value">the value to set the cookie</param> 
    public virtual void SetCookieValue(string value) 
    { 
     //EnsureCookie(); 

     ResponseCookie.Value = value; 

     SetExpiration(); 
    } 

    /// <summary> 
    /// Get the default value (the first value) of the cookie 
    /// </summary> 
    /// <remarks> 
    /// Getting the value only returns the first value (values[0]) because it has no key. 
    /// </remarks> 
    /// <returns>System.String</returns> 
    public virtual string GetCookieValue() 
    { 
     //EnsureCookie(); 

     string returnValue = ""; 

     if (RequestCookie.Values.Count > 0) 
     { 
      returnValue = RequestCookie.Values[0]; 
     } 

     return returnValue; 
    } 

    /// <summary> 
    /// Set a key/value pair 
    /// </summary> 
    /// <param name="key">the key for the pair</param> 
    /// <param name="value">the value to assign to the key</param> 
    public virtual void SetKeyValue(string key, string value) 
    { 
     //EnsureCookie(); 

     ResponseCookie.Values.Set(key, value); 

     SetExpiration(); 
    } 

    /// <summary> 
    /// Get a value for a given key 
    /// </summary> 
    /// <param name="key">the key to find a value of</param> 
    /// <returns>System.String</returns> 
    public virtual string GetKeyValue(string key) 
    { 
     //EnsureCookie(); 

     return RequestCookie.Values[key]; 
    } 

    /// <summary> 
    /// Expire the cookie 
    /// </summary> 
    public virtual void Expire() 
    { 
     //Setting the expiration does not remove the cookie from the next request 
     ResponseCookie.Expires = DateTime.Now.AddDays(-1); 
    } 
} 

Мой шифрования слоя (батареи не включены)

internal sealed class EncryptedCookie : BaseCookie 
{ 
    private string decryptedCookieName; 

    new public string Value 
    { 
     get 
     { 
      if (Configuration.CookieConfiguration.Cookies[decryptedCookieName].EnableEncryption) 
      { 
       return Encryption.DecryptQueryString(base.Value); 
      } 
      else 
      { 
       return base.Value; 
      } 
     } 
     set 
     { 
      if (Configuration.CookieConfiguration.Cookies[decryptedCookieName].EnableEncryption) 
      { 
       base.Value = Encryption.EncryptQueryString(value); 
      } 
      else 
      { 
       base.Value = value; 
      } 
     } 
    } 

    public EncryptedCookie(string cookieName) 
     : base(cookieName) 
    { 
     decryptedCookieName = cookieName; 

     if (Configuration.CookieConfiguration.Cookies[decryptedCookieName].EnableEncryption) 
     { 
      CookieName = Encryption.EncryptQueryString(cookieName); 
     } 

     EnsureCookie(); 
    } 

    public EncryptedCookie(string cookieName, ExpirationMode expirationMode) 
     : base(cookieName, expirationMode) 
    { 
     decryptedCookieName = cookieName; 

     if (Configuration.CookieConfiguration.Cookies[decryptedCookieName].EnableEncryption) 
     { 
      CookieName = Encryption.EncryptQueryString(cookieName); 
     } 

     EnsureCookie(); 
    } 

    public override string GetCookieValue() 
    { 
     if (Configuration.CookieConfiguration.Cookies[decryptedCookieName].EnableEncryption) 
     { 
      return Encryption.DecryptQueryString(base.GetCookieValue()); 
     } 
     else 
     { 
      return base.GetCookieValue(); 
     } 
    } 

    public override void SetCookieValue(string value) 
    { 
     if (Configuration.CookieConfiguration.Cookies[decryptedCookieName].EnableEncryption) 
     { 
      base.SetCookieValue(Encryption.EncryptQueryString(value)); 
     } 
     else 
     { 
      base.SetCookieValue(value); 
     } 
    } 

    public override void SetKeyValue(string key, string value) 
    { 
     if (Configuration.CookieConfiguration.Cookies[decryptedCookieName].EnableEncryption) 
     { 
      base.SetKeyValue(Encryption.EncryptQueryString(key), Encryption.EncryptQueryString(value)); 
     } 
     else 
     { 
      base.SetKeyValue(key, value); 
     } 
    } 

    public override string GetKeyValue(string key) 
    { 
     if (Configuration.CookieConfiguration.Cookies[decryptedCookieName].EnableEncryption) 
     { 
      return Encryption.DecryptQueryString(base.GetKeyValue(Encryption.EncryptQueryString(key))); 
     } 
     else 
     { 
      return base.GetKeyValue(key); 
     } 
    } 
} 

И, наконец, слой управления печенья, который оборачивает все это.

public sealed class Cookie 
{ 
    string cookieName; 

    public Cookie(string cookieName) 
    { 
     this.cookieName = cookieName; 
    } 

    public void AppendCookie() 
    { 
     EncryptedCookie cookie = new EncryptedCookie(cookieName); 

     cookie.AppendNewCookie(); 
    } 

    public void SetAttribute(string attributeName, string attributeValue) 
    { 
     EncryptedCookie cookie = new EncryptedCookie(cookieName); 

     cookie.SetKeyValue(attributeName, attributeValue); 
    } 

    public void SetValue(string value) 
    { 
     EncryptedCookie cookie = new EncryptedCookie(cookieName); 

     cookie.SetCookieValue(value); 
    } 

    public string GetValue() 
    { 
     EncryptedCookie cookie = new EncryptedCookie(cookieName); 

     return cookie.GetCookieValue(); 
    } 

    public string GetAttribute(string attributeName) 
    { 
     EncryptedCookie cookie = new EncryptedCookie(cookieName); 

     return cookie.GetKeyValue(attributeName); 
    } 
} 

Существует также настраиваемая конфигурация, которая помогает настроить файлы cookie. Вот как это выглядит:

<cookie> 
     <cookies> 
      <!-- enableEncryption: [ true | false ] --> 
      <!-- expirationMode: [ SlidingExpiration | NoExpiration ] --> 
      <!-- timeout: the timeout in minutes (Default 30)--> 
      <!-- httpOnly: [ true | false ] --> 
      <!-- secure: [ true | false ] --> 
      <add name="MyCookie" enableEncryption="true" expirationMode="SlidingExpiration" timeout="64800" domain="" httpOnly="true" path="" secure="false" /> 
     </cookies> 
    </cookie> 

Теперь мой код выглядит примерно так в моем веб-приложение:

public int MyId 
    { 
     get 
     { 

      Cookie cookie = new Cookie(ConfigurationHelper.Cookies.MyCookie); 

      int myId= 0; 
      try 
      { 
       Int32.TryParse(cookie.GetAttribute(BILLERID_KEY), out myId); 
      } 
      catch (System.NullReferenceException) 
      { 
       //do nothing on purpose. 
      } 

      return myId; 

     } 
     set 
     { 
      Cookie cookie = new Cookie(ConfigurationHelper.Cookies.MyCookie); 

      cookie.SetAttribute(MY_KEY, value.ToString()); 
     } 
    } 

    public void SetMyId(int myId) 
    { 
     Cookie cookie = new Cookie(ConfigurationHelper.Cookies.MyCookie); 

     cookie.SetAttribute(MYID_KEY, myId.ToString()); 

     cookie.AppendCookie(); 
    } 

Я называю свойство первым, чтобы увидеть, если идентификатор пользователя был установлен. Этот вызов выполняется на каждой странице. Затем на другой странице пользователь может аутентифицироваться, и я установил идентификатор в файл cookie. Все работает локально, но если я попал на главную страницу на сервере (где id выполняет поиск по id), а затем аутентифицируется, значение cookie не задано. Он остается пустым.

+0

Win 7 и Win Server 2003 очень разные - Win 7 имеет IIS7, а сервер использует IIS6. Вы запускаете это в Cassini (сервер Visual Studio) или в локальном IIS? – davisoa

+0

На сервере с установленными двумя файлами cookie и конфигурацией, указанными выше, один из них задан как «путь», а другой - «/ MyVirtualDir» в качестве пути. Настройка пути к файлу cookie не изменила этого. – Josh

+0

@ davisoa - Да, Cassini на локальном и IIS6 на сервере. Однако код был разработан для .net 2.0, а библиотека - обновлена ​​до 4.0. – Josh

ответ

1

Есть проблема, которую вы не вызывая

cookie.AppendCookie(); 

в наборе аксессору для MyId? Вы вызываете его в методе SetMyId.

+0

http://msdn.microsoft.com/en-us/library/ms178194.aspx говорит, что мне не нужно. Я могу изменить файл cookie непосредственно в коллекции. – Josh

+0

Но вы используете метод Get для извлечения файла cookie, а не элементов доступа к элементам, которые используются в примере. Я думал, что использовать Get для извлечения файла cookie означает, что вам нужно было использовать Set для обновления cookie в коллекции файлов cookie Response. –

+0

Поведение было очень странным. Он работал, потом он остановился. Я собираюсь отказаться от вышеуказанного кода и сделать это так, как говорится в статье MSDN. – Josh

1

Файл cookie создается, когда вы проверяете его на HttpContext.Current.Response. Я работал над этим, вставив копию файла cookie в HttpContext.Current.Items, когда я его установил. Затем, когда мне нужно проверить, было ли оно установлено или нет, я проверяю элементы вместо Response.Cookies.

Не самое элегантное решение, но оно выполняет свою работу.

+0

Даже если манекен был создан, когда я смотрю на него, я затем вытаскиваю его и пытаюсь установить в нем значения. Не имеет смысла, что это не позволит мне это сделать. - Ну, это происходит локально, просто не на сервере. – Josh

 Смежные вопросы

  • Нет связанных вопросов^_^