Posts Tagged ‘multi-tenancy’

Multi Presentation (tenancy) Websites for c#

So you want to build a single web application that can be used multiple times and deployed once? Have you ever built a site, only to have another customer request to have it replicated with some minor changes? One possibility is to copy the files into another directory, make changes as needed and deploy. Of course a month later your customer requests a bug fix or functionality changes to approximately the same file that now exists in two sites. Wouldn’t it be nice to have one set of files that you could change and have the change reflected on all your applications? Creating a multi presentation project might be for you.

In a Nutshell (the short version)

To make a fairly long story short, we will be creating an httpmodule that, upon being called checks to see if an application level variable for the application version has been set. If it finds that the application setting variable is null, the system will attempt to look up a record for itself inside the web.config file using the Request.URL.Host string. If the string exists as an app setting, we can grab the value (in this example I will store a numeric ID to pull up a database record for settings. Once you have your settings the only question is how to get all those sites pointed at the same set of files. To get this accomplished I use IIS to create multiple sites pointed at the same set of files with host header records to store what the incoming host name is for the site.

Let’s Break This Down…

Since this type of site takes some doing, lets go over the steps first:

  1. Create your project
  2. Create an CustomAppSettings class to store some basic information about the different versions of your site.
  3. Create a method to fill that CustomAppSettings class per site.
  4. Modify your site based on the version of the site your users have requested.
  5. Setup IIS to handle the different sites.

Create your project

There isn’t really anything tricky going on in the early stages here. Since we will be using the settings in our web.config file, go ahead and add a System.Configuration reference to your project. The System.Configuration reference will allow us to make calls to ConfigurationManager.AppSettings.
Adding the System.Configuration reference

Create an AppSettings class to store some basic information about the different versions of your site.

So now we want to create a class that will store some basic information like an application id, the site’s address, and any other settings that one might need for the application version to run independently of the other applications you will be hosting.

	public class CustomAppSettings
	{
		public int ID { get; set; }
		
		//This property will be to store the short name of our application version
		//for a template directory, if we choose to use one.
		public string ApplicationReference { get; set; }
		
		//This is the hostname our application is coming in on.
		public string HostName { get; set; }
	}	

This app settings class can be expanded significantly to include all sorts of specific settings like you would normally put in a single presentation project like SMTP servers, etc.

Create a method to fill that CustomAppSettings class per site.

We now need a method to store our CustomAppSettings into our Application object for easy access later. In a recent post (Storing User Information in Session for c#) I wrote up a class called GlobalVars that makes accessing untyped storage objects like Application and Session easier. For this project, let’s use the GlobalVars class to create a placeholder for our CustomAppSettings Object.

	public static class GlobalVars
	{
		public static CustomAppSettings CurrentAppSettings
		{
			get
			{
				object o = HttpContext.Current.Application["_CurrentAppSettings"];
				if (o != null)
				{
					//one could potentially do thier setting of the currentapp variable here
					//using the HTTPContext.Current object.
					return (CustomAppSettings)o;
				} 
				return null;
			}
		}
	}

With this code we can just type in GlobalVars.CurrentAppSettings.HostName to easily access our CurrentAppSettings whenever we need it.

The next part of this step is to get the CurrentAppSettings application level variable stored so it doesn’t return null all the time. To do this, we are going to create an httpmodule.

public class ConfigureApp : IHttpModule
{
	public void Dispose()
	{

	}

	public void Init(System.Web.HttpApplication context)
	{
		context.BeginRequest += context_BeginRequest;
	}

	public void context_BeginRequest(object sender, EventArgs e)
	{
		HttpApplication application = (HttpApplication)sender;
		Uri url = application.Context.Request.Url;

		//plug on the application setting the first time someone pulls up the app.
		if (CurrentAppSettings == null)
		{
			//check to see if our value exists in the web.config file.
			string config = ConfigurationManager.AppSettings[url.Host.ToString().ToLower()];
			
			//Setup a long variable for our try parse.
			long holderid = 1;
			if (!string.IsNullOrEmpty(config))
			{
				Int64.TryParse(config, out holderid);
				if (holderid <= 0)
				{
					holderid = 1;
				}
			}
			
			//this is where we would load our id from the db and set
			//the different settings.
			CurrentAppSettings = LoadMyApp(holderid);
		}
	}
}

While building the httpmodule you might have noticed that there is a call in there to the web.config. We actually need to make a couple different changes to the web.config file, first the reference to run the new httpmodule in our web app and, second, the application url references. Let’s take a look at those now.

Registering the http module

	<system.web>
		<httpModules>
		  <add name="ConfigureApp" type="ConfigureApp" />
		</httpModules>
	  </system.web>
	<system.webServer>
		<modules>
		  <add name="ConfigureApp" type="ConfigureApp" />
		</modules>
	</system.webServer>

Note that there are two different registrations here. The first is for iis6, the second for iis7. You will also note that the name and type both reference the name of our class from the http module.

Creating Our Application References

<configuration>
	<appSettings>
		<add key="MySite1.MyDomain.com" value="1"/>
		<add key="www.MySite1.MyDomain.com" value="1"/>
		<add key="MySite2.MyDomain.com" value="2"/>
		<add key="localhost" value="1"/>
	</appSettings>
</configuration>

We have added a few different settings into our appSettings section here to let the httpmodule know which app should point at which application. An important note here is that any individual host header record one makes into IIS needs to be entered here as, without it, the record won’t pull up from the web.config. You will also note that I have included a reference for “localhost”. If you are doing work on the different versions of the site in Visual Studio, the local web server will show up “localhost”. You can alter which version of the site you want to work on by changing the value of the localhost app setting.

Create the Site in IIS

We are on the home stretch now. Open up IIS and add a web site.
Adding a new web site
Note we are using a host header record here. Point your new web site to your file set and hit Ok. Your new web site will be up on that new host header record. To put up more sites on the same set of files, rinse and repeat!