views:

823

answers:

9

We have a legacy ASP.net powered site running on a IIS server, the site was developed by a central team and is used by multiple customers. Each customer however has their own copy of the site's aspx files plus a web.config file. This is causing problems as changes made by well meaning support engineers to the copies of the source aspx files are not being folded back into the central source, so our code base is diverging. Our current folder structure looks something like: OurApp/Source aspx & default web.config
Customer1/Source aspx & web.config
Customer2/Source aspx & web.config
Customer3/Source aspx & web.config
Customer4/Source aspx & web.config
...

This is something I'd like to change to each customer having just a customised web.config file and all the customers sharing a common set of source files. So something like: OurApp/Source aspx & default web.config
Customer1/web.config
Customer2/web.config
Customer3/web.config
Customer4/web.config
...

So my question is, how do I set this up? I'm new to ASP.net and IIS as I usually use php and apache at home but we use ASP.net and ISS here at work.

+1  A: 

Use an external source control application and keep rolling out updates as required.

It isn't really a good idea to let your live site be updated by support engineers in real time anyway.

Brody
A: 

Source control is used and I intend to retrain the support engineers but is there any way to avoid having multiple copies of the source aspx files? I hate that sort of duplication!

Danielb
+1  A: 

I know it might seem annoying, but the duplication is actually a good thing. The problem here is with your process, not with the way the systems are setup.

Keeping the sites separate is actually a good thing. Whilst it looks like "duplication" it's actually not. It's separation. Making changes in the production code by your support engineers should be actively discouraged.

You should be looking at changing your process to change once deploy everywhere. This will make everything a lot easier for you in the long run.

To actually answer your question, the answer is no, you can't do it. The reason is that web.config isn't designed to store user level settings, it's designed to store per application instance settings. In your case, you need an application instance per user which means separate config files.

For your system to work, you need to be able to preemptively tell the application which config file to use, which isn't possible without some sort of input from the user.

lomaxx
A: 

Depending on what is actually in the web config, and what settings differ between customers, you could opt to use a single web config, and store other customer specific configuration options in a database or some other custom xml/text file. As long as the specific customer settings in the web.config don't have to do anything with how IIS operates, and you are just using it to store values, then this solution might work out well for you.

Kibbee
+2  A: 

If you're dead-set on the single app instance, you can accomplish what you're after using a custom ConfigurationSection in your single web.config. For the basics, see:

Example XML might be:

<YourCustomConfigSection>
   <Customers>
     <Customer Name="Customer1" SomeSetting="A" Another="1" />
     <Customer Name="Customer2" SomeSetting="B" Another="2" />
     <Customer Name="Customer3" SomeSetting="C" Another="3" />
   </Customers>
</YourCustomConfigSection>

Now in your ConfigSection Properties, expose Name, SomeSetting, and Another. When the Property is accessed or set, use a condition (request domain or something else that uniquely identifies the Customer) to decide which to use.

With the proper implementation, the app developers don't need to be aware of what's going on behind the scenes. They just use CustomSettings.Settings.SomeSetting and don't worry about which Customer is accessing the app.

Corbin March
The missing piece here is: how do you identify which customer is connected?
Brian MacKay
Give each their own subdomain or virtual. If that's not possible, identify the Customer during log-on - maybe a role or identifier tied to their app session.
Corbin March
I really like the idea of identifying them by subdomain or virtual domain.
Danielb
Although I think I will store the customer settings in the database layer rather than files.
Danielb
A: 

If I understand correctly, it sounds like you have multiple deployments (one for each client) where the only difference is the web.config, right?

First off, although I don't know your unique situation, I would generally urge you to stay with separate installs. It usually allows much more flexibility. Off the top of my head: are you ever going to have customizations, or different clients running different versions? Are you sure? The easiest way to stay flexible here is to keep going with separate installs.

In my opinion, it isn't ugly at all if your practices are aligned properly. Based on some things you mentioned, you have trouble in that area - obviously, possible source control buy-in/training issues. But you are aware of that. I would also take a hard look at your deployment procedures and so on. I have a feeling you might have further issues in that area, and I mean absolutely no offense.

That said, let's say you want to move forward with this.

You didn't say whether all the clients share a single common database, but I'm thinking no, since designing that type of system is often not worth the extra complexity (which can be severe in systems of any size) so people often opt to keep them separate.

What that means is that you have store your connection string somewhere. Usually that would be web.config... So that seems to break our plan.

Really, the apparent elegance of this situation is almost always wildly offset by the challenges it introduces. If I thought about it hard enough, I could maybe find a way around this by introducing another database that intelligently manages connection strings or maybe delving into keeping all your login info directly in web.config (which is possible but... not ideal), however my gut says the work will be wasted because some day you will end up going back to how you're doing it now.

Also: changing code directly in production is obviously not the best practice here. But you if you are on a monolithic shared platform with any amount of traffic, that can never ever ever happen. Food for thought.

Let me know if I'm missing something!

Brian MacKay
+1  A: 

Well, you could try to utilize hardlinks: http://msdn.microsoft.com/en-us/library/aa365006.aspx ... you asked for it.

Another question that might be of interest: http://stackoverflow.com/questions/323702/techniques-for-distributing-aspnet-user-controls-across-projects

mksoagi
A: 

Thank you all again for your answers. After reading through them and having a think what I think I will do is leave the multiple instances alone for now and I will try to improve our update process first. then I will develop a new version of the application that has the user configuration information in the database layer and then pick the user based on the request domain or URL as someone suggested. That way I can have a single application instance supporting multiple different client configurations cleanly.

As most of the client configuration data is really presentation or data source related, nothing complicated. I think we ended up with multiple application instances mostly because the original programmer hadn't been expecting multiple customers and didn't design for that so when someone came along later and added a second customer they just duplicated the application which is wasteful as each instance is about 99.99% identical to the original.

Danielb
A: 

I am implementing this as we speak.

In the main web.config, I have 1 item per installation. It points me toward the custom config file I built for each client (and toward the custom masterpage, css, images, etc).

Using WebConfigurationManager.OpenWebConfiguration, I open the new webconfigs in their subdirectories. I determine which one to use by using System.Web.HttpContext.Current.Request.Url.OriginalString, and determining the uRL that called me. Based on that URL, I know which web.config to use.

From that point forward the clients all use the same codebase. They have their own databases too.

The idea of having to update 30-40 installations when we make an update scares the death out of me. We do not want to support 30-40 codebases, so there won't be customization beyond the master page, css, and images.

I wrote a custom class lib that knows how to switch to the proper webconfig, and read the custom section I built with all our settings.

The only issue I have now is the FormsAuthentication Cookie. I need to be able to switch that as well. Unfortunately, the property for the name is read only