I have one ASP.NET web application running at the web server root which provides multiple (similar) web sites by using URL redirection. To give a real world example:
Wouldn't the simplest solution be to update references to Session objects that are company dependent with a dynamic key based on the Company?
For example...
Session["IsTest"]
becomes
Session[createSessionKey(CompanyID, "IsTest")]
where createSessionKey generates the corresponding key possibly by a simple concatenation of Company and Key
This would then differentiate the two or more companies by accessing the session via generated keys.
Following the example above, company1 would access the "IsTest" Session variable via the key "company1_IsTest" and company2 would access the "same" "IsTest" Session variable via the key "company2_IsTest".
Hopefully you have don't have things like Session("IsTest") littered all over your code base as that would make refactoring your code a real pain.
Typically I abstract my Session variables into a strongly typed class. Then my session management is contained in one place.
Using the idea of having a base Page class and overriding the Session property is a nice way to go if all you Session variables are to be company specific. Though if you can determine if a particular Session key is a generic Session variable or company specific then it may still be workable.
Creating your own Session wrapper, or a custom Session Provider would be the right answer. But, you may be able to hack it by moving existing session data as the user goes to another company with an HttpModule hooked to PostAcquireRequestState.
Basically, compare this ProductsFromCompany with the previous ProductsFromCompany. If they're different, move all of the existing Session values to a Dictionary<string, object>
(or prepend a company id to them) and restore the saved Dictionary<string, object>
for this ProductsFromCompany to Session.
Something like:
void PostAcquireRequestState(object sender, EventArgs e) {
if (Session["ProductsFromCompany"] != Request["ProductsFromCompany"]) {
var lastCompanySession = new Dictionary<string, object>(Session.Count);
var sessionKeys = Session.Keys;
foreach (string key in sessionKeys) {
if (key == "CompanyState" || key == "ProductsFromCompany") {
continue;
}
lastCompanySession[key] = Session[key];
Session.Remove(key);
}
Session["CompanyState"].Add(Session["ProductsFromCompany"], lastCompanySession);
var thisCompanySession = Session["CompanyState"][Request["ProductsFromCompany"]];
foreach (string key in thisCompanySession.Keys) {
Session[key] = thisCompanySession[key];
}
Session["CompanyState"].Remove(Request["ProductsFromCompany"]);
Session["ProductsFromCompany"] = Request["ProductsFromCompany"];
}
}
I suggest writing your own session wrapper. Here's a good example from Martin in another question:
How to access session variables from any class in ASP.NET?
Depending on how you're adding and retrieving items to and from the Session (and possibly dependent on whether you're deriving your pages from a common base page), you might be able to do a custom object that wraps the session without breaking all of your code (as mentioned in your first option where you have a session wrapper implemented as a hash map keyed by site). If you create a custom object and expose it as "Session" at the base page level, it will take precedence over the Session object you inherit from the Page class. Then, your custom object can override the indexers and make the determination where in the hashmap to store this object based on the request url of the current http context.
If you're not deriving from a common base page, this kinda goes out the window because then you'd have to either implement a base page for all pages to derive from or add code to each page to get a reference to your object. Just and idea...