Attention: We are retiring the ASP.NET Community Blogs. Learn more >

BUG FIX - Personalization - Error when attempting to remove multiple values

I fixed and uploaded a bug in the Personalization assembly today. The fixed assembly has been uploaded as version 1.0.1.0.

One of the cool things (which wasn't actually working:) about the Personalization assembly is that it allows you to easily remove a single item from a the Keys collection of a Cookie Value with many sub-keys using the following syntax:

Personalization p = new Personalization( "MyStore" ) ;
p.Remove( "foo" ) ;

 

In this instance, the sub-key "foo" will get removed from the "MyStore" key values. The trick is to remove the single sub-key but to re-write all previous sub-keys. Under the covers, when a user calls Remove, Personalization cycles through the sub-keys to determine which ones to keep and which one it can chuck out.

The bug that existed was that, everytime I re-wrote the values I was (effectively) loading the cookie from the Request object which meant that, if I removed 2 items in succession that the first item would get re-written back in; you could only delete a single key at time. As an example, the following code would remove the value for "bar" but fail to remove the value for "foo":

Personalization p = new Personalization( "MyStore" ) ;
p.Remove( "foo" ) ;
p.Remove( "bar" ) ;

 

I've implemented the following fix (refer emboldened lines):

// the medium that values are being persisted to.
private HttpCookie Cookie
{
    get
    {
        HttpContext ctx = HttpContext.Current ;
        if( ctx == null ) return null ;
        if( this._cookie == null )
        {
            if( ctx.Request.Cookies[StoreName] == null )
                ctx.Response.Cookies[StoreName].Expires = this.ExpiresOn ;
            this._cookie = ctx.Request.Cookies[StoreName] as HttpCookie ;
        }
        return this._cookie ;
    }
}

 

...and then, I obviously update the local instance when I make changes:

/// <summary>
/// Internal method used to refresh the cookie values after they have been accessed
/// </summary>
/// <remarks>
/// This is the only place that read/write access is performed on the cookie</remarks>
/// <param name="userKey">The key whose value to set</param>
/// <param name="userValue">The value to set</param>
private void RewriteValues( string userKey, string userValue )
{
    HttpContext ctx = HttpContext.Current ;
    if( ctx == null ) return ;
    HttpCookie oldCookie = this.Cookie ;
    HttpCookie newCookie = new HttpCookie(this.StoreName) ;
    if( oldCookie.HasKeys )
    {
        string[] keys = oldCookie.Values.AllKeys ;
        foreach( string key in keys )
        {
            if( key == userKey  )
            {
                // only write the new value if it's not null
                if( userValue != null )
                {
                    newCookie[key] = userValue ;
                }
            }
            else
            {
                // re-add the previous value
                newCookie[key] = oldCookie[key] ;
            }
        }
    }
    // if the collection didn't contain the key... add it.                
    if( newCookie[userKey] == null && userValue != null )
        newCookie[userKey] = userValue ;
        
    // update the sliding timescale
    newCookie.Expires = this.ExpiresOn  ;    
    this._cookie = newCookie ;
    ctx.Response.Cookies.Add( newCookie ) ;
}

No Comments