Pankaj Sharma

Staying Connected In A Disconnected World...

  Home  |   Contact  |   Syndication    |   Login
  4 Posts | 0 Stories | 10 Comments | 0 Trackbacks

News

Archives

Post Categories

Blogs i follow

Communities

Wednesday, April 25, 2012 #

The title and scope of the article may force you to argue as web.config files are already there to fulfill the purpose of keeping application specific configuration if any. But i encountered a case where the application's configuration settings in appSettings section grew larger and larger. Providing a flexibility to customer to change any setting value on his own turned out to be problem as it cluttered the web.config file. File eventually became large enough that a setting key value happened to miss the user's eye.


I tried to find out all the possibilities of removing app settings from web.config to another configuration file. I found out an easy approach where in a new .xml file was created and a piece of custom code that loaded file and assigned the values to corresponding properties of a custom class. Let talk the real business of how i did it.

A new configuration file AppConfigurations.xml was created in App_Data folder of the application. Format the file as shown below -

ViewAppconfig

A new code file was created under Configuration folder with the name AppConfigurations.cs. This file is a wrapper class of the xml file. It contains as many public read only variables as tags in xml file. Each class member corresponds the appConfig tag in xml. You can see all the read only members have been assigned values in the constructor of the class.

       1:  public static class AppConfigurations 
       2:      { 
       3:          public static readonly string AppBasePath; 
       4:          public static readonly string AuthenticationKey; 
       5:          public static read only string ErrorLogFilePath;       
       6:          static AppConfigurations() 
       7:          { 
       8:              DataSet file = new DataSet(); 
       9:              string path = AppDomain.CurrentDomain.BaseDirectory + @"App_Data\AppConfigurations.xml"; 
      10:              file.ReadXml(path); 
      11:              if (file.Tables.Count > 0) 
      12:              { 
      13:                  DataTable cFile = file.Tables[0]; 
      14:                  cFile.PrimaryKey = new DataColumn[] { cFile.Columns[0] }; 
      15:                  AppBasePath = cFile.Rows.Find("BasePath")["value"].ToString(); 
      16:                  AuthenticationKey = cFile.Rows.Find("AuthenticationKey")["value"].ToString(); 
      17:                  ErrorLogFilePath = cFile.Rows.Find("ErrorLogFilePath")["value"].ToString(); 
      18:              } 
      19:          }        
      20:      } 
The read only fields allows to be assigned values once only in the initializer or in the constructor of the class. I choose the static class as app configuration settings are going to be same for the entire application hence does not need any copy.

You can test if the settings are properly read or not by showing them on a page.

ViewAppConfigUI

Here is the code that displays the text on the Default.aspx page.

   1:  public partial class _Default : System.Web.UI.Page 
   2:      { 
   3:          protected void Page_Load(object sender, EventArgs e) 
   4:          { 
   5:              System.Text.StringBuilder sb = new System.Text.StringBuilder(100); 
   6:              sb.Append("<p>AppBasePath :" + Configuration.AppConfigurations.AppBasePath + "</p>"); 
   7:              sb.Append("<p>AuthenticationKey :" + Configuration.AppConfigurations.AuthenticationKey + "</p>"); 
   8:              sb.Append("<p>ErrorLogFilePath :" + Configuration.AppConfigurations.ErrorLogFilePath + "</p>"); 
   9:              ltContent.Text = sb.ToString(); 
  10:          } 
  11:      } 

But this implementation is reasonably different from the one using web.config file. As soon as any change is done in web.config file appdomain is restarted and new fresh value of app settings are available in the application.

Lets emulate this behaviour by using filesystemwatcher object and binding the changed event to a handler. As soon as any change is done in the AppConfigurations.xml file file’s changed event is raised and in the event handler we unload the application domain. It forces to restart the app domain on the subsequent requests.

   1:  public static class AppConfigurations 
   2:      { 
   3:          public static readonly string AppBasePath; 
   4:          public static readonly string AuthenticationKey; 
   5:          public static readonly string ErrorLogFilePath; 
   6:          static System.IO.FileSystemWatcher fsw; 
   7:          static AppConfigurations() 
   8:          { 
   9:              DataSet file = new DataSet(); 
  10:              …… 
  11:              SetupFileWatcher(AppDomain.CurrentDomain.BaseDirectory + "App_Data"); 
  12:          } 
  13:          static void SetupFileWatcher(string dirPath) 
  14:          { 
  15:              fsw = new System.IO.FileSystemWatcher(dirPath); 
  16:              fsw.IncludeSubdirectories = false; 
  17:              fsw.Filter = "*.xml"; 
  18:              fsw.NotifyFilter = System.IO.NotifyFilters.LastWrite; 
  19:              fsw.Changed += new System.IO.FileSystemEventHandler(fsw_Changed); 
  20:              fsw.EnableRaisingEvents = true; 
  21:          } 
  22:          static void fsw_Changed(object sender, System.IO.FileSystemEventArgs e) 
  23:          { 
  24:              try 
  25:              { 
  26:                  AppDomain.Unload(AppDomain.CurrentDomain); 
  27:              } 
  28:              catch 
  29:              { 
  30:                  //Log the exception 
  31:              } 
  32:          } 
  33:      }

Happy coding!!

 


Sunday, August 14, 2011 #

Recently i caught in a peculiar situation where i need to modify the check constraint expression to include more criteria to be validated through T-SQL. Although there is no declarative command or mechnism to modify the expression except dropping and recreating the check constraint. One exception is to use the Sql Management studio to modify it in design mode.

But modifying using design mode was out of scope. The actual work was to alter or modify the defintion of a check constraint created with an implicit name that is given by sql server itself when one is not provided by the user.

Lets first create a test table that contains 2 columns first is Name and another is Profile. Profile column is used to hold if user is a Administrator 'A' or Operator 'O'.

Create table Test(
[Name] nvarchar(10),
[Profile] char(1) Check([Profile] = 'A' OR [Profile] = 'O')
)

Insert Into Test Values('User1','A')
Insert Into Test Values('User2','O')

Select * from Test

A new table is created and two rows are created in the table. One thing is to be given an attention is that the check constraint is not given a name. So Sql server will do the job and give a name in the format something like "CK__Test__Profile__XXXXXXXX'.

As the application evolves, suppose a new profile is required for say Guest. I take the initial 'G' that will denote the Guest. I write an insert statement to create a new row in Test table with the guest profile as follows

Insert Into Test Values('User3','G')

Msg 547, Level 16, State 0, Line 1
The INSERT statement conflicted with the CHECK constraint "CK__Test__Profile__59063A47". The conflict occurred in database "db_gei_test", table "dbo.Test", column 'Profile'.
The statement has been terminated.

 

It throws the error that says value conflicted with the check constraint. Most obvious solution that comes to mind is to extend the expression but for that we need to have a name to identify the check constaint on the column.

An alternative solution could be to, infact solution i need, is to write a T-SQL to first find the name of the check constraint defined on the Table Test and column [Profile]. Second step is to alter table and recreate the check constraint with the extended expression. Here we go

declare @constraintName nvarchar(100)
select @constraintName = OBJECT_NAME(scc.OBJECT_ID)   
from sys.check_constraints scc
Inner Join sys.columns sc on scc.parent_object_id = sc.object_id and scc.parent_column_id = sc.column_id
where OBJECT_NAME(scc.parent_object_id) = 'Test' and sc.[name] = 'Profile'
and type_desc = 'CHECK_CONSTRAINT'

exec('Alter table Test Drop Constraint ' + @constraintName);

ALTER TABLE [dbo].[Test] ADD Constraint [CK_Test_Profile]
    CHECK([Profile] = 'A' OR [Profile] = 'O' OR [Profile] = 'G')

Now run the insert command for creating a user with guest profile.

Insert Into Test Values('User3','G')

Command runs successfully and creates a new row in the Test table, it could be verified by firing a select command on the table.

Hope this tip could make your task of modifing a check constraint easier.


Friday, April 15, 2011 #

Recently i faced a bizarre problem in IIS 7.0 where none of my configured local sites worked. Hitting the starting URL of each application took me to the general error page. Infact when i tried to check if IIS is running or not i tried with http://localhost. But no success i still got the same error page.



The IIS Manager was launched and checked if everything was okay? I found everything perfect over there. But still IIS was not working and none of my application was launching.

Then i tried several workarounds.

    * Thought that binding of IIS might got lost so i fired the aspnet_regiis -i command from VS comand Prompt to re register the IIS with the lastest version of .NET.
    * Uninstalled the IIS from the machine, then reinstalled the IIS. It did not work. Then again i executed the command above to register the IIS.

Inspite of trying everything possible as per my understanding it did not seem to work. Then i suddenly found that the Default Web Site is not running. So i tried to start it by right clicking on the default site node and then selecting the Start option from Manage Web Site.



Infact the situation got worse and i was staring another error pop up that looked like



That turned me crazy, as everything was working until last time. What i did that really crashed everything. I investigated and i found out that i created a new solution in VS 2010 and used the URL as it is that i was using to visit the application in IE. It contained the %20 in the root URL of the application. Web Browser replaces the space in the URL with the equivalent code that is %20.



That typographical error in URL caused all the problem.

I removed the Virutal Directory URL http://localhost/My%20Application from IIS by right clicking, selecting Remove. Then recreated one with correct Virtual URL http://localhost/My Application.

It then allowed to start the Default Web Site successfully and silently. Everything worked perfectly afterwards. I could see the default page of IIS start on hitting the http:/localhost. All my applications started working.

It seems that IIS does not like special characters in the Virtual Directory URLs. I will investigate it further as what was wrong with that encoded URL.


Tuesday, April 05, 2011 #

This is my first post, so i am not sure how to proceed. I was very anxious to post something relevant to IT community but due to work loads or a thought that everything is available on net here or there keeping me away to post. But there is always a first time .

Recently when i was working on a change requirement i had to change a table data in a manner in which field data toggles. Essentially it was a production entity table like parts in a batch manufacturing. So the table contained a field [Status] that was of bit type. 1 denoted the true hence active, 0 denoted the false hence inactive state.

I wanted to change the status of parts to inactive which were active and to active which were inactive. There i tried and found the bitwise operator ~ (tilde) in SQL Server that would toggle the bit value. If it is 1 then it would change it to 0 or vice versa.

Lets take an example to demonstrate how it could be used. Lets create a simple table that would hold the details of users who are active or inactive based on their Status.

create table Users(
[Id] int not null IDENTITY,
[Name] varchar(50) not null,
[Status] bit not null
)

INSERT INTO Users VALUES('Setup',1)
INSERT INTO Users VALUES('Operator',0)
INSERT INTO Users VALUES('Engineer',1)
INSERT INTO Users VALUES('Guest',0)

If we fire a select query it would return the following output:

Now if one wants to toggle the status of users means change active users to inactive and inactive users to active, it would require one single query using bitwise operator tilde(~).

Update Users Set [Status] = ~[Status]

Verify it by executing select statement on the table.

Select * from Users