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 ) ; }