2

I have an asp.net-MVC website with a SQL server backend. There are a 100 different tables and this site works for an organization of 300 people.

We now want to use it for another organization and there then a technical issue with how to expand the site. Here are some of the requirements:

Background:

There are many tables that would be completely reused across both organizations but also many tables where i would have to add a filter to make sure i only get the records back that are relevant to that particular org.

Given that, I have the Single or Multiple Database decision to make like this question or as discussed on Joel's podcast (I am trying to keep it to a single database if possible as there are users that want to look across both organizations) so I sort of have to go with shared in the multi tenant database decision

As discussed in the podcast, as an example there is a People table. That is simple as it just adding a "where Person.Org = "A" into the query if i was just querying the people table. But it also affects any query that has a direct or indirect join with the People table. So lets say I have a Car table and that has a Owner column (which would be a foreign key into People table), If i have a dropdown of Cars I would first have to join with People and then add that filter (before it was just Select * from Cars). I am using nhibernate but you get the point

Question:

My focus now is that I am trying to determine how to have an additional switch around all of my asp.net-mvc Controller actions to support this new organization. So if i have 40 Controllers and each controller has 10 Actions, i have to update 400 actions and every page (and all of the view and javascript code to points to certain URLs. I have I need to first determine which "mode" i am in to determine if i should query for org 1 or org 2

I don't want to go through every single Controller Action and add a new parameter or a route that is "Org Name" or something like that so I wanted to see if there were any idea. Even if it ran two different web sites I still would have to have this global switch if i want to have this run in a single code base.

Is there suggestions so I can avoid adding additional parameter on every controller action?

Community
  • 1
  • 1
leora
  • 188,729
  • 360
  • 878
  • 1,366
  • Maybe, when instantiating your repository, you could just dynamically activate some NH query filter depending on some new optional client parameter in your route. I don't know if it would work, but this would lead to minimal change to your code. That's just random thoughts, though. – jbl Mar 09 '13 at 10:16

2 Answers2

1

Assuming that you have a limited set of tables (at least, fewer tables that Controller actions) and that your CRUD operations are centralized, you could set the orgId in the session when the user logs in and use that value to filter on all the queries?

shrisha
  • 445
  • 2
  • 7
  • but where would it get the orgId from? Lets say I have a Dropdown of Orgs on my site.master . . how would I pass that to all controllers? – leora Mar 09 '13 at 04:12
  • The controller action that handles the org selection can proceed to set the orgId in the session. – shrisha Mar 09 '13 at 05:15
0

Would adding the Customer ID / Name in the route help? I worked on a similar application, and my route pattern looks like this:

{customer}/{controller}/{action}/{id}

Because you already have a code base, you could add the customer as optional parameter:

{controller}/{action}/{id}/{customer}

...
customer = UrlParameter.Optional

Either way, you will need to provide the route values in your Url actions. In my case, all the controllers inherit from a base controller which identifies the customer, checks security, authorization, etc. via custom attributes or in code. The base controller sets a protected property called CurrentCustomer which contains all the information required. It works pretty well, because same interface can be accessed by the customer users or by admin users. The admin users can access information for multiple customers and the application works with multiple databases (one database can contain multiple customers).

I think for you would be better to have separate databases for each customer, to avoid passing customer id to the SQL statements / SPs (and make a lot of code changes). You will just need to identify at runtime which database to work with, based on the customer.

dan radu
  • 2,772
  • 4
  • 18
  • 23
  • but your recommendation is requiring me to go into every action and update it with an additional parameter and every client side ajax call and change to add that additional parameter. I was hoping to see if there was a way to avoid that – leora Mar 09 '13 at 00:39
  • No, you don't have to add this parameter to every action, because it will be optional. The base controller will use this parameter in its `Initialize` method: `string customerName = this.RouteData.Values["customer"].ToString();` – dan radu Mar 09 '13 at 00:42
  • I thought a bit more and I was wondering if you can identify which organization the users belong to, when they log in (asking them to enter the org name wouldn't be nice). If so, let the account controller set the current organisation and use it for data access. This way, you don't need to change the routing at all. You will need to store this info in the session, cookie, etc. to avoid passing it to every controller action. In my case, storing state was totally forbidden because of the load balancing or security issues. – dan radu Mar 09 '13 at 00:57
  • if i have different URLs (abc.mysite.com or def.mysite.com might be able to differentiate) – leora Mar 09 '13 at 01:31
  • I think it will work. You just need to get the sub-domain name, which is probably the organization name and use it as the switch for your data access. This [SO question](http://stackoverflow.com/questions/278668/is-it-possible-to-make-an-asp-net-mvc-route-based-on-a-subdomain) might help you. – dan radu Mar 09 '13 at 05:12