Wednesday, August 5, 2009

Modifying <appSettings> in web.config programatically using AJAX, JQuery, JSON

Recently I was working on a ASP.Net project where there was a need to update the values stored in <appSettings> section in the web.config file programtically. Specifically, there is a maintenance screen with a tabbed interface and one of the tab was called 'Configuration' which would provide the user an interface to 'Add' and 'Update' <appSettings> values. One of the main requirements was that it has to be completely AJAX enabled and use of 'UpdatePanels' are not allowed.

You can find lot of resources on the web explaining how to do 'modify web.config programatically' and its an easy thing to do. But the main challenge lies in making it completely AJAX enabled (and there is not much information out there on this topic). And the steps to acheive that are as follows:
  1. Create a server method (e.g. GetConfigSettings()) to enumerate all the <appSettings> values
  2. Create a custom serializale type called 'AppplicationSetting' containing public members 'Key' and 'Value' and for each appsettings entry create a corresponding 'AppplicationSetting' objects and put it in a generic list (named 'AppSettingsList') of type'ApplicationSetting'
  3. Serialze the list data (from Step 2) in JSON format using JavaScriptSerializer
  4. Invoke the GetConfigSettings() from client side JavaScript on page load and retrieve the data (use PageMethods)
  5. Process the data (from Step 3) and create an user interface (as shown in Fig 1)
  6. Provide ability to add new values
  7. Process all the newly entered value and updated value on the client side ensuring duplicates are handled properly and create a JSON object
  8. On clicking 'Save' button, invoke a server method (e.g. SaveConfigSettings()) passing configuration settings (in form of a the JSON object)
  9. On the server side, deseriaize the data back to list of objects of type 'AppplicationSetting'
  10. Loop through the list (from Step 9) and add or update the corresponding key/value appSettings entry
  11. Save the web.config file
Now let's get cracking at the code (the fun stuff!!!). Let's start by looking at at the UI screen
(Fig 1)

The UI screen is self-explanatory. It consists of two textboxes for 'key' and 'value' for each of the existing appSettings value. Clicking on the 'Add' button adds a new pair of texboxes to enter a new key,value pair.

Clicking on the 'Cancel' reloads the form with the original (existing) values.
Define the public method GetConfigSettings() and mark it as a 'WebMethod()', make it 'Shared' so that is can be invoked from clientside JavaScript using PageMethods.

<WebMethod()>_
Public Shared Function GetConfigSettings() As String
Dim status As String = String.Empty
Dim bsrtent As ServiceLayer = New ServiceLayer
status = bsrtent.LoadConfigSettings()
Return status
End Function

<WebMethod()> _
Public Shared Function SaveConfigSettings(ByVal newconfigsettings As String) As String
Dim status As String = String.Empty
Dim bsrtent As ServiceLayer = New ServiceLayer
status = bsrtent.SaveConfigSettings(newconfigsettings)
Return status
End Function

Once we have marked a server method as 'WebMethod' we no longer can work with non-static members because the method is 'Shared'. So we need to define a class (essentially a service layer), instatiate an object of the service layer and invoke public instance member of the class to do the necessary functions.

The LoadConfigSettings function of the ServiceLayer is as follows:


The SaveConfigSettings() function of ServiceLayer is as follows:


Now to the client side JavaScript code (where all the action is!!!). We assume you have properly referred JQuery library in your project, use ScriptManager on your page and have a form with a div id='#tab-Config'. The JavaScript code in itself provides lots of insight into JQuery and its usage. (I'll blog about some of them in greater details in future)

$(function() {
PageMethods.GetConfigSettings(LoadConfigSettingsSuccess);
});

function LoadConfigSettings() {

if (CONFIGSETTINGS) {
var count = CONFIGSETTINGS.length;
var configrow;
if (count > 0) {
$('#tab-Config').empty();
var msg = '<b class="MSGRED"><u>Note</u>: Changing the web.config file will cause the application to re-start.</b>';

var configtable = $('<table><tr><td class="funcheader" align="center">Key</td><td class="funcheader" align="center">Value</td></tr></table>');
for (var i = 0; i < count; i++) {
var configrow = $('<tr></tr>');
var key = CONFIGSETTINGS[i].Key;
var val = CONFIGSETTINGS[i].Value;
var keytxt = $('<td><input type="text" name="configkey" id="configkey' + key + '" class="namemaptextbox" value="' + key + '"/></td>');
var valtxt = $('<td><input type="text" name="configval" id="configval' + key + '" class="namemaptextbox" value="' + val + '"/></td>');
configrow.append(keytxt);
configrow.append(valtxt);
configtable.append(configrow);
}
var buttontable = $('<table></table>');
var addkeybutton = $('<td><input type="button" class="clickbutton" name="addconfigbutton" id="addconfigbutton" value="Add"/></td>');
var saveconfigbutton = $('<td><input type="button" class="clickbutton" name="saveconfigbutton" id="saveconfigbutton" value="Save" onclick="SaveConfigSettings();"/></td>');
var cancelconfigbutton = $('<td><input type="button" class="clickbutton" name="cancelconfigbutton" id="cancelconfigbutton" value="Cancel" onclick="LoadConfigSettings();"/></td>');
buttontable.append($('<tr></tr>').append(addkeybutton).append(saveconfigbutton).append(cancelconfigbutton));

$('#tab-Config').append(msg).append(configtable).append(buttontable);

//Reset the width of the value textbox
$('div#tab-Config input[id^=configval]').each(function() { $('#' + this.id).css('width', '200px'); });

addkeybutton.click(function() {
var newkeytxt = $('<td><input type="text" name="configkey" class="namemaptextbox" value=""/></td>');
var newvaltxt = $('<td><input type="text" name="configval" class="namemaptextbox" value="" style="width:200px"/></td>');
configtable.append($('<tr></tr>').append(newkeytxt).append(newvaltxt));
});
}

}
}

function SaveConfigSettings() {
var keys = new Array();
var vals = new Array();
var newconfigsettings = "[";
$('#tab-Config input[name=configkey]').each(function() {
keys.push(this.value);
});
$('#tab-Config input[name=configval]').each(function() {
vals.push(this.value);
});

//Generate the JSON Objects
var prevkey = "";
for (var i = 0; i < keys.length; i++) {
//Check for duplicate
var dupkey = false;
for (var j = 0; j < i - 1; j++) {
if (keys[j] === keys[i]) {
dupkey = true;
break;
}
}
if (!dupkey) {
if ((keys[i] !== '') && (vals[i] !== '')) {
newconfigsettings += '{"Key":"' + keys[i] + '","Value":"' + vals[i].replace(/\\/g, '\\\\') + '"},';
prevkey = keys[i];
}
}
else {
i++; //found duplicate so skip the index for both both <key> and <val>
}

}
newconfigsettings += '{"Key":"EOF","Value":""}]';

PageMethods.SaveConfigSettings(newconfigsettings, SaveConfigSettingsSuccess, SaveConfigSettingsFailure);
}

function SaveConfigSettingsSuccess(result) {
var success = eval(result);
if ((success) && (success.Message)) {
alert(success.Message);
PageMethods.GetConfigSettings(LoadConfigSettingsSuccess);
}
}

function SaveConfigSettingsFailure(result) {
var err = eval(result);
alert(err.get_message());
}

function LoadConfigSettingsSuccess(result) {
eval(result);
LoadConfigSettings();
}

And that is all (really!!!) to create a pure AJAX enabled UI interface to programtically modify web.config appSettings entries. The same concept can be extended to update/modify other sections of the web.config (or any data) in an ASP.Net application.



No comments:

Post a Comment