Rajnish Noonia

Category: Tips

Tips and tricks

  • Enterprise configuration management

    Almost every application requires some form of configuration information. This information can be as simple as a database connection string or as complex as multipart and hierarchical user preference information. How and where to store an application’s configuration data are questions you often face as a developer.

    Any large enterprise application has many moving blocks. They all need to be configured for a proper working of the application. As the application size increases or for scalability the same configuration has to be repeated in different applications. For most applications once the configuration has been changed the application needs to be restarted.

    Sample Code (create a blank console project, add json.net nuget)

    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace CM
    {
        // configuration management API, 
        //1. allow clients specify typesafe models for configuations
        //2. Store flat data on server (table) which is easy to edit
        //3. can be extended to have inheritance of values (overrides)
        //4. can be extended to lock / unlock certain property by admins etc.
        
        class Program
        {
            //Sample configuration model
            internal class SampleConfigModal
            {
                public SampleConfigModal()
                {
                    Address = new Address();
                }
                public string Name { get; set; }
                public Address Address { get; set; }
                public int Age { get; set; }
    
    
            }
            public class Address
            {
                public string Street { get; set; }
    
            }
    
            // this is how client api will look like
            static void Main(string[] args)
            {
                // sample client code
                var data = new SampleConfigModal() { Name = "Rajnish", Age = 18, Address = new Address() { Street = "Oxley" } };
    
                // save Configuration
                SaveConfiguration("app", "section", data);
    
                //get Configuration
                var data2 = GetConfiguration("app", "section");
            }
    
            // Client side framework api -> call to rest end point
            private static T GetConfiguration(string appName, string SectionName) where T : new()
            {
                var defaultValue = new T();
                var samplePayload = JsonConvert.SerializeObject(defaultValue);
                var payload = GetConfiguration(appName, SectionName, samplePayload);
                return JsonConvert.DeserializeObject(payload);
            }
    
            // Client side framework api -> call to rest end point
            private static void SaveConfiguration(string appName, string SectionName, T data)
            {
                var payload = Newtonsoft.Json.JsonConvert.SerializeObject(data);
                SaveConfigurationa(appName, SectionName, payload);
            }
    
    
            //---------------------------------------- Server Code -------------------------- 
            //-------------- server has no knowledge of configuration structure or model
    
            private static Dictionary<string, string> storage;
    
            private static void SaveConfigurationa(string appName, string SectionName, string payload, string enumForHierarchyLevel = null)
            {
                // transformer
                var section = string.Format("{0}.{1}", appName, SectionName);
                var data = (JObject)JsonConvert.DeserializeObject(payload);
                var keyValueData = Flatten(data, section);
    
                // check if user has permission for level overrides
                // store with proper overides
    
                // store the flat list in sql or data 
                //| KEY |           |Value|            |OverrideType| - default,sysadmin,appadmin,groups,user etc
                //app.section.Name, Rajnish
                //app.section.Address.Street, Oxley
                //app.section.Age, 18
    
                storage = keyValueData;
            }
    
            private static string GetConfiguration(string appName, string SectionName, string samplePayload)
            {
                var section = string.Format("{0}.{1}", appName, SectionName);
                var data = (JObject)JsonConvert.DeserializeObject(samplePayload);
                var keyValueSample = Flatten(data, section);
                // update data from sql or data store
                // apply property override rules and get value from overrides if exists
                var keyValueData = keyValueSample.Select(x => new KeyValuePair<string, string>(x.Key, storage[x.Key]));
    
                //read these
                //app.section.Name, Rajnish
                //app.section.Address.Street, Oxley
                //app.section.Age, 18
    
                UnFlatten(data, section, keyValueData);
    
                var formatedData = JsonConvert.SerializeObject(data);
                /*
                 * {
                      "Name": "Rajnish",
                      "Address": {
                        "Street": "Oxley"
                      },
                      "Age": "18"
                    }
                 * */
                return formatedData;
    
            }
            
            // Server side json helper
    
            private static void UnFlatten(JObject jsonObject, string prefix, IEnumerable<KeyValuePair<string, string>> data)
            {
                foreach (var item in data)
                {
                    var keyName = item.Key.Substring(prefix.Length + 1);
                    var storageValue = item.Value;
                    if (keyName.Contains("."))
                    {
                        var keys = keyName.Split('.');
                        var jtoken = (JToken)jsonObject;
                        foreach (var k in keys)
                        {
                            jtoken = jtoken.SelectToken(k);
                        }
                        ((JValue)jtoken).Value = storageValue;
                    }
                    else
                    {
                        jsonObject[keyName] = storageValue;
                    }
                }
            }
    
            private static Dictionary<string, string> Flatten(JObject jsonObject, string prefix)
            {
    
                IEnumerable jTokens = jsonObject.Descendants().Where(p => p.Count() == 0);
                Dictionary<string, string> results = jTokens.Aggregate(new Dictionary<string, string>(), (properties, jToken) =>
                {
                    properties.Add(string.Format("{0}.{1}", prefix, jToken.Path), jToken.ToString());
                    return properties;
                });
                return results;
            }
        }
    }
    
    
  • Windows 8: TopMost window

    TopMost

    I am working on my next ambitious project “MouseTouch” which is multi touch simulator application for windows 8 platform and intended to increase the productivity if you are running windows 8 on non-touch device.

    This will bring the touch feature of windows 8 to life even if you are using mouse pad.

    The first challenge is how to render something on top of metro start menu items?

    So if you want to create a true topmost window which can float even on top of windows 8 metro apps here are the simple steps..

    1. Create WPF visual studio application (or any other window app )
    2. Set TopMost=True for MainWindow
    3. Right-click on your project in the Solution Explorer
    4. Select “Add New Item” from the context menu.
    5. Choose “Application Manifest File” from the list of options in the dialog box that appears.
    6. Right-click on your project in the Solution Explorer and click “Properties” (or double-click on the “Properties” item under your project).
    7. Under the first tab (“Application”),select your app.manifest file from the drop-down box labeled “Manifest”.
    8. Set the, <requestedExecutionLevel level=”asInvoker” uiAccess=”true” />

    The next part is to create a certificate and install it in trusted root authorities.

    1. Create certificate
      1. makecert -r -pe -ss PrivateCertStore-n “CN=TopMost.com” topmost.cer
    2. Import certificate to (Local Machine) trusted root certification authorities using mmc.exe.

    Now sign your executable using the certificate, either by using the command, or using visual studio (check the delay sign flag).

    1. Signtool sign /v /s PrivateCertStore /n TopMost.com /t http://timestamp.verisign.com/scripts/timestamp.dll TopMost.exe

    Now copy the TopMost.exe to trusted location like c:Windows or program files and execute the TopMost.exe..

    Still struggling ..

    Ok if , executable is not signed or certificate is not installed properly, you see following exception

    referralError

     

     

     

     

     

     

     

    To avoid this exception, open mmc.exe, add certificates snap-in>Select Computer account>Local Computer>

    Go to trusted root certification authorities>certificates>right click > tasks and import the certificate ..

    CertInstall

  • Determine an Assembly’s Fully Qualified Name

    While extending the Visual Studio development you might be working on an extension that would be using the fully qualified (4-part) name of an assembly.
    Below are the simple steps to extend the visual studio
    Open Visual Studio
    Go to Tools –> External Tools
    Click on “Add” to add a tool, and put in the following values:
    Title: Get Qualified Assembly Name
    Command: Powershell.exe
    Arguments: -command “[System.Reflection.AssemblyName]::GetAssemblyName(“$(TargetPath)”).FullName”

    When this menu item is selected (Tools->Get Qualified Assembly Name), the assembly name is given in the output window.
    It should look like

    MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c2534056547c8962

     

  • Fixing @@SERVERNAME in SQL Server

    If @@servername returns null or return wrong host name, execute below mentioned sql Query.


    DECLARE @Current SysName
    Select @Current = Convert(varchar(128), SERVERPROPERTY(‘ServerName’) )
    IF(@Current <> @@SERVERNAME)
    BEGIN
    EXEC sp_dropserver @@SERVERNAME
    EXEC sp_addserver @server=@Current,@local = ‘local’
    EXEC master..xp_cmdshell ‘ECHO NET STOP MSSQLSERVER > restartSQL.bat’, no_output
    EXEC master..xp_cmdshell ‘ECHO NET START MSSQLSERVER >> restartSQL.bat’, no_output
    EXEC master..xp_cmdshell ‘restartSQL.bat’, no_output
    –Connection with sql break here
    END

    — Check if every thing is correct
    SELECT @@Servername
    SELECT SERVERPROPERTY(‘ServerName’)

  • Export data from corrupted database

    Below is the sql script to import data from source database into target database, It is assumed that you have both the databases on single server.The source database is current database & few tables are corrupted whereas the traget database is created from old backup for target database.since their is corruption ,it is not possible to take backup of current database. This script imports back data (only) from source to target database. You need to only replace 3 lines of the script (12th line from bottom).
    Download script from here

     
    
    ------------- Create helper functions -----------------------------
    
    IF EXISTS (select * from dbo.sysobjects where id = object_id(N'[dbo].[Mig_ImportTable]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
    DROP PROCEDURE [dbo].[Mig_ImportTable]
    GO
    
    CREATE PROC dbo.Mig_ImportTable @Database SYSNAME, @Table SYSNAME AS
    	SET NOCOUNT ON
    
    	DECLARE @Column SYSNAME
    	DECLARE @SQL NVARCHAR(4000)
    	DECLARE @colSQL NVARCHAR(4000)
    	DECLARE @IsIdentity BIT
    	DECLARE @IsTableIdentity BIT
    
    	SET @colSQL = ''
    	SET @SQL=''
    	SET @IsTableIdentity = 0 --false
    	SET @IsIdentity = 0 --false
    
    	PRINT 'Table Migration Started for :' + @Table + ' in ' + @Database
    
    	DECLARE curMoveDown CURSOR
    	LOCAL FORWARD_ONLY
    	OPTIMISTIC FOR
    	SELECT column_name,COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity')as IsIdentity FROM information_schema.columns
    	WHERE UPPER(table_name ) = UPPER(@Table)
    
    	OPEN curMoveDown FETCH NEXT FROM curMoveDown INTO @Column,@IsIdentity
    	WHILE @@FETCH_STATUS = 0
    	BEGIN
    		SET @colSQL = @colSQL + '[' + @Column + '],'
    		SET @IsTableIdentity = @IsTableIdentity | @IsIdentity
    		IF (@IsTableIdentity = 1) BREAK
    		FETCH NEXT FROM curMoveDown INTO @Column,@IsIdentity
    	END
    	CLOSE curMoveDown
    	DEALLOCATE curMoveDown 
    
    	IF(LEN(@colSQL)>1)
    	BEGIN
    		SET @colSQL = LEFT(@colSQL,LEN(@colSQL) - 1)
    
    		IF(@IsTableIdentity = 1) SET @SQL = @SQL + 'SET IDENTITY_INSERT ' + @Table + ' ON '
    		SET @SQL = @SQL + '	ALTER TABLE ' + @Table + ' DISABLE TRIGGER ALL '
    		SET @SQL = @SQL + '	ALTER TABLE ' + @Table + ' NOCHECK CONSTRAINT ALL '
    		SET @SQL = @SQL + '	TRUNCATE TABLE ' + @Table + '  '
    		IF(@IsTableIdentity = 1)
    			SET @SQL = @SQL + '	INSERT INTO ' + @Table + ' (' +  @colSQL + ') SELECT '+  @colSQL + ' FROM ' + '[' + @Database + '].[dbo].[' + @Table + '] '
    		ELSE
    			SET @SQL = @SQL + '	INSERT INTO ' + @Table + ' SELECT * FROM ' + '[' + @Database + '].[dbo].[' + @Table + '] '
    		IF(@IsTableIdentity = 1) SET @SQL = @SQL + '	SET IDENTITY_INSERT ' + @Table + ' OFF '
    		SET @SQL = @SQL + '	ALTER TABLE ' + @Table + ' ENABLE TRIGGER ALL '
    		SET @SQL = @SQL + '	ALTER TABLE ' + @Table + ' CHECK CONSTRAINT ALL '
    
    		EXEC sp_executesql @SQL
    		PRINT 'Table migrated :' + @Table
    	END
    	ELSE
    		PRINT 'No Column found :' + @Table + ' (SQL = ' + @colSQL + ')'
    
    	PRINT 'Table Migration finished for :' + @Table
    GO
    
    IF EXISTS (select * from dbo.sysobjects where id = object_id(N'[dbo].[Mig_ImportDatabase]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
    DROP PROCEDURE [dbo].[Mig_ImportDatabase]
    GO
    
    CREATE PROC dbo.Mig_ImportDatabase @Source SYSNAME AS	
    
    	DECLARE @SERVER SYSNAME
    	DECLARE @INSTANCE SYSNAME
    	DECLARE @FULLNAME SYSNAME
    	DECLARE @DBNAME SYSNAME
    	DECLARE @cmd varchar(1000)
    	DECLARE @SQL Nvarchar(1000)
    	DECLARE @Table Nvarchar(100)
    	DECLARE @Result INT
    
    	SET NOCOUNT ON
    
    	CREATE TABLE [#Mig_FailedTables] ( [name] SYSNAME NOT NULL ) ON [PRIMARY]
    
    	SELECT @SERVER = CONVERT(SYSNAME, SERVERPROPERTY('servername'))
    	SELECT @INSTANCE = IsNull('',CONVERT(SYSNAME, SERVERPROPERTY('InstanceName')))
    	SELECT @DBNAME = DB_NAME()
    
    	IF(Len(@INSTANCE)>0) SET @FULLNAME = @SERVER + '' + @INSTANCE
    	ELSE SET @FULLNAME = @SERVER
    
    	Print 'Migration started from database [' + @SOURCE + '] to database [' + @DBNAME + '] on server  ' + @FULLNAME
    
    	--Cursor to loop throw all tables of Target database (current database)
    	DECLARE CurTables CURSOR LOCAL FORWARD_ONLY
    	OPTIMISTIC FOR
    	SELECT NAME from dbo.sysobjects where OBJECTPROPERTY(id, N'IsUserTable') = 1 order by Name
    
    	OPEN CurTables FETCH NEXT FROM CurTables INTO @Table
    	WHILE @@FETCH_STATUS = 0
    	BEGIN
    		Print 'Migrating table ' + @Table
    		SET @cmd = 'ECHO Exec [Mig_ImportTable] ''' + @Source + ''',''' + @Table + '''  > DbMig.sql'
    		EXEC @Result = master..xp_cmdshell @cmd, no_output
    
    		SET @cmd = 'ECHO GO  >> DbMig.sql'
    		EXEC @Result =  master..xp_cmdshell @cmd, no_output
    
    		SET @cmd = 'ECHO @ECHO OFF  > DbMig.cmd'
    		EXEC @Result =  master..xp_cmdshell @cmd, no_output
    
    		SET @cmd = 'ECHO osql -E -b -S "' + @FULLNAME +'" -d "' + @DBNAME +'" -i "DbMig.sql" >> DbMig.cmd'
    		EXEC @Result =  master..xp_cmdshell @cmd, no_output
    
    		SET @cmd = 'ECHO EXIT ERRORLEVEL >> DbMig.cmd'
    		EXEC @Result =  master..xp_cmdshell @cmd, no_output
    
    		SET @cmd = 'CMD /c "DbMig.cmd>>DbMig.Log"'
    		EXEC @Result = master..xp_cmdshell @cmd, no_output
    		IF (@Result <> 0)
    			Insert into #Mig_FailedTables (Name) values (@Table)
    		FETCH NEXT FROM CurTables INTO @Table
    
    	END
    	CLOSE CurTables
    	DEALLOCATE CurTables
    	Print 'Migration Finished..'
    	SELECT Name as [Failed Tables] FROM #Mig_FailedTables
    	DROP TABLE #Mig_FailedTables
    
    GO
    
    ------------- Migration of data starts from here ------------------
    
    ----------------------------------------------------------------------------------------------------------------------------------
    
    USE TargetDatabase						-- Target Database  	** Change This
    Exec Mig_ImportDatabase 'SourceDatabase'			-- Source Database  	** Change This - Import Complete database
    EXEC Mig_ImportTable 'SourceDatabase','SpecificTableName'	-- SpecificTableName  	** Change This - Import Single Table
    ----------------------------------------------------------------------------------------------------------------------------------