Wednesday, January 13, 2010

Identifying whether execution context is win or web

When writing components which targets both web and desktop applications, there might be instances where there is need to check under which context the code is running.

Checking System.Web.HttpContext.Current won't work always. If the code is running under the context of main thread this always works. But if a thread is spawn, in the new thread System.Web.HttpContext.Current will return null even if it is running under web context.

Some debugging showed me that System.Web.HttpRuntime.AppDomainId is the right candidate for checking this. System.Web.HttpRuntime.AppDomainId returns null when the code is running under windows context, but always returns a non-null string value while running under web context regardless of whether the code is running under main thread or a spawned thread.

So the below piece of code can be used to check whether the code is running under web context.
/// <summary>
/// Specifies whether the current execution context is Web.
/// </summary>
/// <returns>True if current context is Web.</returns>
public bool IsWebApplicationContext()
{
    return !string.IsNullOrEmpty(System.Web.HttpRuntime.AppDomainId);
}

Tuesday, January 12, 2010

Simple WCF Service, Host and Client

We will create a simple WCF service which will be hosted in a custom console application. A win form application is used as the WCF client.

WCF Service
We will start with a ServiceContract interface which will be implemented by a ServiceBehavior class.

[ServiceContract()]
public interface IUserService
{
    [OperationContract]
    void AddUser(UserDataContract user);
    [OperationContract]
    void RemoveUser(int userId);
    [OperationContract]
    List<UserDataContract> GetUsers();
    [OperationContract]
    string Echo(string msg);
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class UserService : IUserService
{
    List<UserDataContract> users = new List<UserDataContract>();

    public void AddUser(UserDataContract user)
    {
        users.Add(user);
        Console.WriteLine(string.Format("User {0} {1} added", user.FirstName, user.LastName));
    }
    public void RemoveUser(int userId)
    {
        for (int i = 0; i < users.Count; i++)
        {
            if (users[i].Id == userId)
            {
                Console.WriteLine(string.Format("User {0} {1} removed", users[i].FirstName, users[i].LastName));
                users.Remove(users[i]);
                return;
            }
        }
        Console.WriteLine(string.Format("User {0} does not exist", userId));
    }
    public List<UserDataContract> GetUsers()
    {
        Console.WriteLine(string.Format("User list returned. {0} users", users.Count));
        return users;
    }
    public string Echo(string msg)
    {
        Console.WriteLine("Invoked with " + msg);
        return "Haaalo, " + msg;
    }
}

Here the service InstanceContextMode is declared as InstanceContextMode.Single to have a singleton behavior.
Please click here for more details for InstanceContextMode in msdn.

Now a DataContract can be created which is the agreement between service and client that abstractly describes the data to be exchanged.

[DataContract]
public class UserDataContract
{
    int id;
    string firstName;
    string lastName;

    [DataMember]
    public int Id
    {
        get { return id; }
        set { id = value; }
    }

    [DataMember]
    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; }
    }

    [DataMember]
    public string LastName
    {
        get { return lastName; }
        set { lastName = value; }
    }
}

WCF Service Host
A Service Host is needed to host the service just created. A simple console application is used as a host here. The below configuration specifies the end points exposed by the service. Different endpoint can be created for different binding.

<configuration>
    <system.serviceModel>
        <services>
            <service name="UserServiceLibrary.UserService">
                <endpoint address="http://localhost:8080/userservice/svc" binding="basicHttpBinding"
                    bindingConfiguration="" contract="UserServiceLibrary.IUserService" />
    <endpoint address="net.tcp://localhost:8081/userservice/svc" binding="netTcpBinding"
                    bindingConfiguration="" contract="UserServiceLibrary.IUserService" />
            </service>
        </services>
    </system.serviceModel>
</configuration>

class Program
{
    static void Main(string[] args)
    {
        using (ServiceHost host = new ServiceHost(
        typeof(UserService), new Uri("http://localhost:8085/userservice")))
        {
            host.Open();

            Console.WriteLine("{0} is open and has the following endpoints:\n",
                host.Description.ServiceType);

            int i = 1;
            foreach (ServiceEndpoint end in host.Description.Endpoints)
            {
                Console.WriteLine("Endpoint #{0}", i++);
                Console.WriteLine("Address: {0}", end.Address.Uri.AbsoluteUri);
                Console.WriteLine("Binding: {0}", end.Binding.Name);
                Console.WriteLine("Contract: {0}\n", end.Contract.Name);
            }
            Console.ReadLine();
        }
    }
}

WCF Win Client
An interactive win form application is used as the client. The below configuration defines the named endpoint configurations used by the ChannelFactory. These addresses should match with the addresses specified earlier with the host configuration.

<configuration>
 <system.serviceModel>
  <client>
   <endpoint name="usHttpEndpoint"
     address="http://localhost:8080/userservice/svc"
     binding="basicHttpBinding"
     contract="UserServiceLibrary.IUserService"/>
   <endpoint name="usTcpEndpoint"
     address="net.tcp://localhost:8081/userservice/svc"
     binding="netTcpBinding"
     contract="UserServiceLibrary.IUserService"/>
  </client>
 </system.serviceModel>
</configuration>

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void btnAdd_Click(object sender, EventArgs e)
    {
        try
        {
            using (ChannelFactory<IUserService> httpFactory = new ChannelFactory<IUserService>("usHttpEndpoint"))
            {
                IUserService svc = httpFactory.CreateChannel();
                UserDataContract user = new UserDataContract();
                user.Id = int.Parse(userId.Text);
                user.FirstName = firstName.Text;
                user.LastName = lastName.Text;
                svc.AddUser(user);
            }
        }
        catch (Exception ex)
        {
            output.Text = ex.Message;
        }
    }

    private void btnDelete_Click(object sender, EventArgs e)
    {
        try
        {
            using (ChannelFactory<IUserService> httpFactory = new ChannelFactory<IUserService>("usHttpEndpoint"))
            {
                IUserService svc = httpFactory.CreateChannel();
                svc.RemoveUser(int.Parse(userId.Text));
            }
        }
        catch (Exception ex)
        {
            output.Text = ex.Message;
        }
    }

    private void btnShowAll_Click(object sender, EventArgs e)
    {
        try
        {
            using (ChannelFactory<IUserService> httpFactory = new ChannelFactory<IUserService>("usHttpEndpoint"))
            {
                IUserService svc = httpFactory.CreateChannel();
                List<UserDataContract> users = svc.GetUsers();
                StringBuilder sb = new StringBuilder();
                foreach (UserDataContract user in users)
                {
                    sb.AppendFormat("{0} {1}/{2}\r\n", user.FirstName, user.LastName, user.Id);
                }
                output.Text = sb.ToString();
            }
        }
        catch (Exception ex)
        {
            output.Text = ex.Message;
        }
    }
}

Below is a snapshot of the client form where in we can add, delete and list the users.


Now the service is ready to be tested. Start the host console application and once ready, start the client to communicate with the service.

Output
After adding 2 users and retrieving the list of users the output will look as below.


Thursday, December 31, 2009

Getting list of applications in a site from IIS metabase

We will start with creating a class for storing the application details.

public class IisWebApplication
{
   private string _Name = "";
   public string Name
   {
      get { return _Name; }
      set { _Name = value; }
   }

   private string _AspNetFrameworkVersion = "";
   public string AspNetFrameworkVersion
   {
      get { return _AspNetFrameworkVersion; }
      set { _AspNetFrameworkVersion = value; }
   }

   private string _Description = "";
   public string Description
   {
      get { return _Description; }
      set { _Description = value; }
   }

   private string _FolderPath;
   public string FolderPath
   {
      get { return _FolderPath; }
      set { _FolderPath = value; }
   }
}

As specified in my earlier post, each web site is assigned a unique integer value. The path for accessing a site will look like IIS://localhost/W3SVC/{site number}. The below method can help in getting the application details associated with a website passed as siteId. You can also specify whether to get details of sub applications.

public List<IisWebApplication> GetWebApplications(int siteId, bool showSubApplications)
{
   _ApplicationPools = GetApplicationPools();

   List<IisWebApplication> webApps = new List<IisWebApplication>();
   string MetabaseRootPath = @"IIS://localhost/W3SVC/" + siteId.ToString() + "/ROOT";
   DirectoryEntry appEntry = null;
   try
   {
      appEntry = new DirectoryEntry(MetabaseRootPath);
      foreach (DirectoryEntry s in appEntry.Children)
      {
         CheckAndAddWebApplication(s, webApps, showSubApplications);
      }
   }
   catch { }
   finally
   {
      if (appEntry != null)
         appEntry.Close();
   }
   return webApps;
}

private void CheckAndAddWebApplication(DirectoryEntry entry, List<IisWebApplication> webApps, bool addSubApplications)
{
   bool reserved = true;
   if (IsWebApplicationEntry(entry))
   {
      reserved = IsReservedWebApplication(entry.Name);
      if (!reserved)
         webApps.Add(GetWebApplication(entry));
   }
   if (entry.Children != null && addSubApplications && !reserved)
   {
      foreach (DirectoryEntry s in entry.Children)
      {
         CheckAndAddWebApplication(s, webApps, addSubApplications);
      }
   }
}

private IisWebApplication GetWebApplication(DirectoryEntry entry)
{
   IisWebApplication webApp = new IisWebApplication();
   webApp.Name = GetApplicationName(entry);
   webApp.AspNetFrameworkVersion = GetAspNetVersion(entry);
   webApp.FolderPath = GetApplicationFolderPath(entry);
   if (_ApplicationPools != null)
   {
      string appPoolName = entry.Properties["AppPoolId"].Value.ToString();
      webApp.ApplicationPool = GetApplicationPoolFromList(appPoolName);
   }
   return webApp;
}

private bool IsWebApplicationEntry(DirectoryEntry entry)
{
   string keyType = entry.Properties["KeyType"].Value.ToString();
   if (keyType == "IIsWebDirectory" || (keyType == "IIsWebVirtualDir" && entry.Properties["Path"].Value != null))
   {
      string[] appNames = GetApplicationName(entry).Split("/".ToCharArray());
      if (appNames[appNames.Length - 1] == entry.Name)
         return true;
   }
   return false;
}

private string GetApplicationName(DirectoryEntry entry)
{
   string appRoot = entry.Properties["AppRoot"].Value.ToString();
   string matchString = "/ROOT/";
   int index = appRoot.ToUpper().IndexOf(matchString);
   if (index > -1)
      return appRoot.Substring(index + matchString.Length);

   return entry.Name;
}

private bool IsReservedWebApplication(string appName)
{
   if (appName.StartsWith("_vti_") || appName == "_private" || appName == "bin" || appName == "Printers"
      || appName == "aspnet_client")
      return true;
   return false;
}

private string GetApplicationFolderPath(DirectoryEntry entry)
{
   string keyType = entry.Properties["KeyType"].Value.ToString();
   if (keyType == "IIsWebDirectory")
   {
      string path = entry.Path;
      string matchString = "/ROOT/";
      int index = path.IndexOf(matchString);
      return "/" + path.Substring(index + matchString.Length);
   }
   else if (keyType == "IIsWebVirtualDir")
   {
      return entry.Properties["Path"].Value.ToString();
   }
   return "";
}

Getting ASP.Net version for this application depends on the version of IIS you are using. In version 7, the runtime version is set for the App Pool. In earlier versions, runtime version is set for individual applications.

If you are using IIS 7, use the following method.
private string GetAspNetVersion(DirectoryEntry entry)
{
   string appPool = s.Properties["AppPoolId"].Value.ToString();
   string metabaseAppPoolPath = "IIS://localhost/W3SVC/AppPools/" + appPool;
   DirectoryEntry appPoolEntry = new DirectoryEntry(metabaseAppPoolPath);
   return appPoolEntry.Properties["ManagedRuntimeVersion"].Value.ToString();
}

The below method can be used for earlier versions.
private string GetAspNetVersion(DirectoryEntry entry)
{
   PropertyValueCollection vals = entry.Properties["ScriptMaps"];
   if (vals == null)
      return "Could not read the frame work version";
   foreach (string val in vals)
   {
      if (val.StartsWith(".aspx"))
      {
         int startIndex = val.ToLower().IndexOf("framework") + 10;
         int endIndex = val.IndexOf("\\", startIndex);
         string version = val.Substring(startIndex, endIndex - startIndex);
         return version;
      }
   }
   return "No version for .aspx files.";
}

Wednesday, December 30, 2009

Getting list of web sites from IIS metabase

Here we are going to see how we can get the list of web sites available using IIS metabase.
We will start with defining the types we are going to use. Class WebSite is used to hold information about a web site and enum ServerState specifies its state. The states are self explanatory.

public class WebSite
{
   private int _Id;
   public int Id
   {
      get { return _Id; }
      set { _Id = value; }
   }

   private string _Name;
   public string Name
   {
      get { return _Name; }
      set { _Name = value; }
   }

   private string _Description;
   public string Description
   {
      get { return _Description; }
      set { _Description = value; }
   }

   private string _ApplicationPool;
   public string ApplicationPool
   {
      get { return _ApplicationPool; }
      set { _ApplicationPool = value; }
   }

   private string _FolderPath;
   public string FolderPath
   {
      get { return _FolderPath; }
      set { _FolderPath = value; }
   }

   private ServerState _ServerState;
   public ServerState ServerState
   {
      get { return _ServerState; }
      set { _ServerState = value; }
   }
}

public enum ServerState
{
   Unknown = 0,
   Starting = 1,
   Started = 2,
   Stopping = 3,
   Stopped = 4,
   Pausing = 5,
   Paused = 6,
   Continuing = 7
}

We can use System.DirectoryServices.DirectoryEntry for accessing IIS metabase. For getting the registered web sites, we need to iterate through the child nodes of "IIS://localhost/W3SVC". A childer is identified as a web site if the SchemaClassName property is IIsWebServer. IIS assigns unique integer number to each websites which typically starts from 1. The Name property provides this value.

public List<WebSite> GetWebSites()
{
   string metabasePath = "IIS://localhost/W3SVC";
   DirectoryEntry root = null;
   List<WebSite> webSites = new List<WebSite>();
   try
   {
      root = new DirectoryEntry(metabasePath);
      bool hasAppPools = HasApplicationPools();
      foreach (DirectoryEntry s in root.Children)
      {
         int siteId;
         if (s.SchemaClassName == "IIsWebServer" && Int32.TryParse(s.Name, out siteId))
         {
            WebSite webSite = new WebSite();
            webSite.Id = siteId;
            webSite.Name = s.Properties["ServerComment"].Value.ToString();
            webSite.Description = s.Properties["ServerComment"].Value.ToString();
            webSite.FolderPath = GetFolderPath(s);
            webSite.ServerState = GetServerState(s.Properties["ServerState"].Value.ToString());
            if (hasAppPools)
            {
               webSite.ApplicationPool = s.Properties["AppPoolId"].Value.ToString();
            }
            webSites.Add(webSite);
         }
      }
   }
   catch { }
   finally
   {
      if (root != null)
         root.Close();
   }
   return webSites;
}

public bool IsValidMetabasePath(DirectoryEntry entry)
{
   try
   {
      if (entry != null && !string.IsNullOrEmpty(entry.SchemaClassName))
         return true;
   }
   catch { }
   return false;
}

public bool HasApplicationPools()
{
   string metabaseAppPoolsPath = "IIS://localhost/W3SVC/AppPools";
   DirectoryEntry appPoolsEntry = new DirectoryEntry(metabaseAppPoolsPath);
   return IsValidMetabasePath(appPoolsEntry);
}

For getting the website root path, we need to read the Path property of its child named ROOT.

private string GetFolderPath(DirectoryEntry server)
{
   foreach (DirectoryEntry s in server.Children)
      if (s.Name.ToUpper() == "ROOT")
         return s.Properties["Path"].Value.ToString();
   return "";
}

private ServerState GetServerState(string serverStatePropertyValue)
{
   switch (serverStatePropertyValue)
   {
      case "1": return ServerState.Starting;
      case "2": return ServerState.Started;
      case "3": return ServerState.Stopping;
      case "4": return ServerState.Stopped;
      case "5": return ServerState.Pausing;
      case "6": return ServerState.Paused;
      case "7": return ServerState.Continuing;
   }
   return ServerState.Unknown;
}

Tuesday, December 29, 2009

Loading assemblies from a shared location

Recently we had a restriction on deploying assemblies to GAC. Our application structure is quite complex where in my team owns the root website and the framework and lots of applications are configured as sub applications (or even multi level sub applications). It is impossible to release the assemblies to individual teams and coordinate. So for solving this issue we have decided to deploy the shared assemblies to a common location and load it dynamically from there.

The approach we have taken is as follows.
Create an http module called SharedAssemblyLauncher. This assembly will be released to all teams and they have to define this module in their web.config.
The root web.config will define a key "SharedAssemblyBaseDirectory" to specify the base shared assembly location from where the probing starts. Each application web.config can override this too. For supporting multiple versions, you can create folders with the version number and then copy the assemblies to that folder. The probling rule is as follows
1. Look under the folder with version number.
2. Look under folder Common.
3. Base directory

We start with creating a new handler for AssemblyResolve for current domain.

public class SharedAssemblyLauncher : IHttpModule
{
   private static string _BaseAssemblyFolder = "";

   static SharedAssemblyLauncher()
   {
      if (HttpContext.Current != null)
      {
         string appRoot = HttpContext.Current.Server.MapPath("~/");
         string webRoot = HttpContext.Current.Server.MapPath("/");
         if (appRoot != webRoot)
            _BaseAssemblyFolder = GetSharedAssemblyBaseDirectoryFromConfigFile(GetSlashEndedFolder(appRoot) + "web.config");
         if (_BaseAssemblyFolder.Trim() == "")
            _BaseAssemblyFolder = GetSharedAssemblyBaseDirectoryFromConfigFile(GetSlashEndedFolder(webRoot) + "web.config");
      }
      AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
   }

   public void Dispose()
   {
   }

   public void Init(HttpApplication context)
   {
   }
}

In assembly resolve handler, the first thing what we will do is loop through the loaded assemblies to look for a match. We've noticed that, in case for a request for embedded resource the version number was not passed, only the assembly name is passed. So if we probe, we might not find any matching assembly. So it is very important to loop through and find a match before the actual probing starts. If no match found on loaded assemblies, probe based on the sequence defined earlier. If no match found while probing, return null so that the framework does its own probing.
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
   Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
   foreach (Assembly assembly in loadedAssemblies)
   {
      if (assembly.FullName == args.Name || assembly.FullName.Contains(args.Name))
         return assembly;
   }

   if (_BaseAssemblyFolder.Trim() == "")
      return null;

   string assemblyFileName = GetAssemblyFileName(args.Name);
   string assemblyVersion = GetAssemblyVersion(args.Name);
   try
   {
      string fileName = string.Format("{0}{1}\\{2}.dll", _BaseAssemblyFolder, assemblyVersion, assemblyFileName);
      if (File.Exists(fileName))
         return GetAssemblyFromPath(fileName);
      fileName = string.Format("{0}Common\\{1}.dll", _BaseAssemblyFolder, assemblyFileName);
      if (File.Exists(fileName))
         return GetAssemblyFromPath(fileName);
      fileName = string.Format("{0}{1}.dll", _BaseAssemblyFolder, assemblyFileName);
      if (File.Exists(fileName))
         return GetAssemblyFromPath(fileName);
   }
   catch { }
   return null;
}

private static string GetSlashEndedFolder(string baseFolder)
{
   return (baseFolder.Trim().EndsWith("\\") ? baseFolder.Trim() : baseFolder.Trim() + "\\");
}

private static string GetSharedAssemblyBaseDirectoryFromConfigFile(string configPath)
{
   XmlDocument configXmlDoc = new XmlDocument();
   if (!File.Exists(configPath))
      return "";
   configXmlDoc.Load(configPath);
   XmlNode baseDirectoryNode = configXmlDoc.SelectSingleNode("/configuration/appSettings/add[@key=\"SharedAssemblyBaseDirectory\"]");
   if (baseDirectoryNode == null)
      return "";
   return baseDirectoryNode.Attributes["value"].Value;
}

private static string GetAssemblyFileName(string assemblyName)
{
   return assemblyName.Split(",".ToCharArray())[0];
}

private static string GetAssemblyVersion(string assemblyName)
{
   string[] parts = assemblyName.Split(",".ToCharArray());
   for (int i = 0; i < parts.Length; i++)
   {
      if (parts[i].Trim().StartsWith("Version="))
      {
         string[] versionParts = parts[i].Split("=".ToCharArray());
         return versionParts[1].Trim();
      }
   }
   return "";
}

private static Assembly GetAssemblyFromPath(string assemblyPath)
{
   return Assembly.LoadFile(assemblyPath);
}

One important thing to remeber here is that never try to read configuration values using ConfigurationManager in this module.

Happy sharing!!!

Monday, December 28, 2009

Use POST instead of GET

Why do we use POST instead of GET?
GET shows lots of ugly names and values in url. Most browsers have some restrictions on the size of url string. The above 2 points make POST a better choice over GET.

We will quickly see, how can we convert our existing GETs to POSTs.

When a new page is to be called we will create a form dynamically, create hidden fields for all the values to be passed and submit it. The following script can help you in achieving this.
Assume that valuesToPost is a javascript array of objects which has fields Name and Value.

function PostIt(valuesToPost, targetUrl)
{
   var form = document.createElement("form");
   form.setAttribute("method", "post");
   form.setAttribute("action", targetUrl);
   for (var i=0; i<valuesToPost.length; i++)
   {
      var hiddenField = document.createElement("input");
      hiddenField.setAttribute("type", "hidden");
      hiddenField.setAttribute("name", valuesToPost[i].Name);
      hiddenField.setAttribute("value", valuesToPost[i].Value);
      form.appendChild(hiddenField);
   }
   document.body.appendChild(form);
   form.submit();
}

We can read these passed values from the page as follows. These dynamically posted values will be available only when IsPostback is false.
So on page_load, the following code can read these posted values.

if(!IsPostback)
{
   string id = GetPostedValue("Id");
   Dictionary<string, string> postedValues = GetPostedValues();
}

public string GetPostedValue(string key)
{
   return Request.Form[key];
}

public Dictionary<string, string> GetPostedValues()
{
   Dictionary<string, string> postedVals = new Dictionary<string, string>();
   foreach (string key in Request.Form.AllKeys)
      postedVals.Add(key, Request.Form[key]);
   return postedVals;
}

Now bye bye to ugly URLs.
Happy POSTing!!!

Secure values stored in hidden fields

It is a common practice to store values in hidden fields when items are edited. Value like id are a common candidate for these operations. Most times modifying these values from client side by script can be dangerous. Here we will look for a solution where in the complete set of values which we have to store and avail on postbacks be saved in a secure way.

The suggested solution is as follows.

First we will define a dictionary which can hold string key value pairs. We will also provide methods for storing and retrieving these values.

private string _KeyStoreName = "__KeyValueStore__";
private Dictionary<string, string> _KeyValues = new Dictionary<string, string>();
public void SetKeyValue(string name, string value)
{
   if (_KeyValues.ContainsKey(name))
    _KeyValues[name] = value;
   else
    _KeyValues.Add(name, value);
}
public string GetValue(string name)
{
   if (_KeyValues.ContainsKey(name))
    return _KeyValues[name];
   return "";
}

public Dictionary<string, string> GetKeyValues()
{
   Dictionary<string, string> keyVals = new Dictionary<string, string>();
   foreach (string key in _KeyValues.Keys)
    keyVals.Add(key, _KeyValues[key]);
   return keyVals;
}

On pre-render, we will serialize the dictionary and encrypt it. This value will be stored in a hidden field which will be generated dynamically.

protected override void OnPreRender(EventArgs e)
{
   StringWriter sw = new StringWriter();
   los.Serialize(sw, _KeyValues);
   string valueToStore = sw.GetStringBuilder().ToString();
   // Encrypt valueToStore to make it secured.
   HtmlInputHidden hid = new HtmlInputHidden();
   hid.ID = _KeyStoreName;
   hid.Name = _KeyStoreName;
   hid.Value = valueToStore;
   Page.Form.Controls.Add(hid);
   base.OnPreRender(e);
}

On pre-init, we will retrieve the hidden field value, decrypt it and deserialize it.
protected override void OnPreInit(EventArgs e)
{
   string storedValue = Request.Form[_KeyStoreName];
   if (!string.IsNullOrEmpty(storedValue))
   {
    // Decrypt storedValue, if you have encrypted it.
    LosFormatter los = new LosFormatter();
    _KeyValues = los.Deserialize(storedValue) as Dictionary<string, string>;
   }
   base.OnPreInit(e);
}

Happy coding!!!