I use a lot of configuration and provider driven services and variables for developing web applications. Let's face it, I don't like to recompile. I recently had the need to share my Web.config settings with the client code, but didn't want to declare a variable for every possible setting, I just wanted to dynamically create the script of configuration settings in some collection and have access to that in my client side code. Because I wanted this collection to act just like a HashTable in System.Collections, I decided to create a JavaScript type to mirror the storage and access paradigm of the HashTable for use in my applications.
The Storage Container
The basic structure of the HashTable is comprised of an enumerable collection of KeyValuePair objects. To mimic this, I had to define my KeyValuePair object on the client. I decided to use Microsoft's AJAX Client Library included in the .NET 3.5 Framework.
KeyValuePair = function(key, value) {
KeyValuePair.initializeBase(this);
// Add custom initialization here
this._key = key;
this._value = value;
}
KeyValuePair.prototype = {
// Returns the current Dialer Status key
get_key : function() {
return this._key;
},
set_key : function(key) {
this._key = key;
},
// Returns the next to execute Dialer Command
get_value : function() {
return this._value;
},
set_value : function(val) {
this._value = val;
},
initialize: function() {
KeyValuePair.callBaseMethod(this, 'initialize');
},
dispose: function() {
KeyValuePair.callBaseMethod(this, 'dispose');
}
}
KeyValuePair.descriptor = {
properties: [ {name: 'key', type: String},
{name: 'value', type: String} ]
}
KeyValuePair.registerClass('KeyValuePair', Sys.Component);
I then had to create the container to wrap a collection, or in JavaScript's case an Array, of these KeyValuePair objects and make them indexed, searchable, and easy to use just like the .NET HashTable class.
HashTable = function() {
HashTable.initializeBase(this);
// Add custom initialization here
this._items = new Array();
this._deletedIndexes = new Array();
this._isDeleted = function(index) {
for (var i = 0; i < this._deletedIndexes.length; i++) {
if (this._deletedIndexes[i] == index) {
return true;
}
}
return false;
}
}
HashTable.prototype = {
// Returns the next to execute Dialer Command
get_value : function(key) {
for (var i = 0; i < this._items.length; i++) {
if (!this._isDeleted(i)) {
var item = this._items[i];
if (item.get_key() == key){
return item.get_value();
}
}
}
return null;
},
set_value : function(key, val) {
for (var i = 0; i < this._items.length; i++) {
if (!this._isDeleted(i)) {
var item = this._items[i];
if (item.get_key() == key){
item.set_value(val);
this._items[i] = item;
}
}
}
},
get_count : function() {
return this._items.length;
},
initialize: function() {
HashTable.callBaseMethod(this, 'initialize');
},
dispose: function() {
this._items = null;
HashTable.callBaseMethod(this, 'dispose');
},
addPair : function(pair) {
if (pair == null) { return; }
var exists = this.get_value(pair.get_key());
if (exists) { return; }
this._items.push(pair);
},
remove : function(key) {
for (var i = 0; i < this._items.length; i++) {
if (!this._isDeleted(i)) {
if (this._items[i].get_key() == key){
this._items[i].set_key(null);
this._items[i].set_value(null);
this._deletedIndexes.push(i);
return;
}
}
}
},
addItem : function(key, value) {
this.addPair(new KeyValuePair(key, value));
}
}
HashTable.descriptor = {
properties: [ {name: 'count', type: Number} ]
}
HashTable.registerClass('HashTable', Sys.Component);
And that's it! With this new client component I can store configuration entries on the client for use by my page's script. I simply do the following on the server, in my code behind in order to create the collection itself.
Client:
// Declare our global config variable
var Config = new HashTable();
ASP.NET Form:
<%=GetConfigScript()%>
Server:
public string GetConfigScript()
{
StringBuilder script = new StringBuilder();
script.AppendLine("<script type=\"text/javascript\">");
script.AppendLine("//<![CDATA[");
foreach (string key in ConfigurationManager.AppSettings.AllKeys)
script.AppendFormat("Config.addItem(\"{0}\",\"{1}\");",
key.Replace(@"\", @"\\"),
ConfigurationManager.AppSettings[key].Replace(@"\", @"\\"));
script.AppendLine("//]]>");
return script.ToString();
}
Conclusion
Now, whenever I want to access a configuration setting on the client, I call Config.get_value("key"); and it returns that value or null, just like using Configuration.AppSettings["key"] or a HashTable to store values by key, I just happened to use it for configuration settings but it could be used any time I need a searchable HashTable for storing key-value pairs.