'clean up any previous data if present
'start with the checkboxes
Dim tblControl As HtmlTable = CType(checkBoxes.Controls(0), HtmlTable)
For Each control As System.Web.UI.Control In tblControl.Controls
If (TypeOf control Is System.Web.UI.HtmlControls.HtmlTableRow) Then
For Each rowControl As System.Web.UI.Control In control.Controls
If (TypeOf rowControl Is System.Web.UI.HtmlControls.HtmlTableCell) Then
For Each cellControl As System.Web.UI.Control In rowControl.Controls
If (TypeOf cellControl Is System.Web.UI.WebControls.CheckBox) Then
Dim chkBox As System.Web.UI.WebControls.CheckBox = CType(cellControl, System.Web.UI.WebControls.CheckBox)
chkBox.Checked = False
End If
Next
End If
Next
End If
Next
I’m not happy with the json.js script from http://json.org so I’m going to write my own.
For future reference, I’m posting the start of my object reflection class.
if(typeof Caliberweb == 'undefined') var Caliberweb = {};
(function(){
if(typeof Caliberweb.Reflection == 'undefined') {
Caliberweb.Reflection = {
getMembers: function(obj,match){
var bucket = [];
for(var i in obj){
if(match(i)) bucket.push(i);
}
return bucket;
},
GetProperties: function(obj){
return this.getMembers(obj, function(member){
return typeof member != 'function';
})
},
GetMethods: function(obj){
return this.getMembers(obj, function(member){
return typeof member == 'function';
});
}
}
}
})();
I’ve always been impressed with Ayende’s LocalData class. I like Ritesh Rao’s vision of local data even more. I loved how he gives the option of application, session, and thread storage. But, I feel like those implementations leave something to be desired from a consumers perspective. So, I’ve come up with a base interface that is inspired by both of the above projects. It also defines an abstract class so I can create new implementations whenever I need to.
The ILocalData interface:
public interface ILocalData
{
object this[object key] { get; set; }
T Get(object key);
bool TryGet(object key, out T value);
T Set(object key, T value);
void Add(object key, object value);
void Remove(object key);
void Remove(params object[] keys);
bool Contains(object key);
void Clear();
}
The IDataBucket interface:
public interface IDataBucket : IEnumerable
{
object this[object key] { get; set; }
bool ContainsKey(object key);
void Remove(object key);
void Clear();
void Add(object key, object value);
bool UseSynchLock { get; set; }
}
The entry point and abstract class:
public class LocalData : BucketData
{
public LocalData(IDataBucket bucket)
: base(bucket)
{}
public LocalData(Func<IDataBucket> bucketProvider)
: base(bucketProvider)
{}
}
public abstract class BucketData : ILocalData, IEnumerable
{
private static readonly object lockInstance = new object();
private readonly Func<IDataBucket> bucketProvider;
protected BucketData(IDataBucket bucket)
: this(() => bucket)
{}
protected BucketData(Func<IDataBucket> bucketProvider)
{
this.bucketProvider = bucketProvider;
}
public IDataBucket Bucket
{
get { return bucketProvider(); }
}
public object this[object key]
{
get { return Do(() => Bucket[key.ToString()]); }
set { Do(() => Bucket[key.ToString()] = value); }
}
public IEnumerator GetEnumerator()
{
return Bucket.GetEnumerator();
}
public T Get<T>(object key)
{
return Do(() =>
{
T value;
TryGet(key, out value);
return value;
});
}
public bool TryGet<T>(object key, out T value)
{
value = default(T);
object data = Bucket[key.ToString()];
if (data == null)
return false;
if (data is T)
{
value = (T) data;
return true;
}
return false;
}
public T Set<T>(object key, T value)
{
return Do(() =>
{
Bucket[key.ToString()] = value;
return value;
});
}
public void Add(object key, object value)
{
Set(key, value);
}
public void Remove(object key)
{
if (Contains(key))
Do(() => Bucket.Remove(key.ToString()));
}
public void Remove(params object[] keys)
{
foreach (object key in keys)
{
Remove(key);
}
}
public bool Contains(object key)
{
return Do(() => Bucket[key.ToString()] != null);
}
public void Clear()
{
Do(() => Bucket.Clear());
}
private V Do<V>(Func<V> function)
{
if (Bucket.UseSynchLock)
{
lock (lockInstance)
{
return function();
}
}
return function();
}
private void Do(Action action)
{
if (Bucket.UseSynchLock)
{
lock (lockInstance)
{
action();
}
}
action();
}
}
With the following, I can finally say goodbye to buggy HttpSessionState code in legacy systems and even support session isolation.
public class HttpSessionDataBucket : IDataBucket
{
private readonly string bucketName;
public HttpSessionDataBucket() : this(typeof (IDataBucket))
{}
public HttpSessionDataBucket(Type forType) : this(forType.FullName)
{}
public HttpSessionDataBucket(string bucketName)
{
this.bucketName = bucketName;
}
private Hashtable Bucket
{
get
{
HttpSessionState session = HttpContext.Current.Session;
object ht = session[bucketName];
if (ht is HashtableDataBucket)
return (Hashtable) ht;
session[bucketName] = ht = new Hashtable();
return ht as Hashtable;
}
}
public object this[object key]
{
get { return Bucket[key.ToString()]; }
set { Bucket[key.ToString()] = value; }
}
public bool ContainsKey(object key)
{
return Bucket[key.ToString()] != null;
}
...
}
ILocalData localData = new LocalData(new HttpSessionDataBucket(typeof(IMenuItem)));
This is obviously still evolving but, for now, I love being able to have an ILocalData instance in my domain objects (most likely not session buckets though) and being able to call “localData.Clear();” without messing up the rest of the system.
It’s amazing how far we’ll go sometimes. Schwew!
-=Code Well
I don’t know why I never realized that merging was possible in the GUI of Visual SVN but, alas, I hadn’t. It turns out it’s been right there in front of my face all along!
Here’s a situation I ran into today.
I have a personal branch (personal repo too) for a feature I’m working on. After the feature was complete and all was green, I want to merge the feature into the trunk. It’s really simple.
First thing you’ll want to do is make sure you have committed your changes to your feature branch.
Next go ahead and switch to the trunk of your repository.
Now you can start the merging process by clicking the “Merge” button (duh.
).
Now the common TortoiseSVN Merge dialog will popup and you can merge like you’re already used to.
-=Code Well


