CHAPTER 12
Putting It All Together
Class model
The framework classes that we used in the examples are:

- High level interfaces
And their common implementations:

- Typical implementations of high level interfaces
Choosing the right tenant identification strategy
All of the tenant identification strategies presented in Chapter 3 have some pros and cons; some require some additional configuration, others only really apply to simple scenarios. Some of the criteria include:
- Ease of testing one or the other tenant
- The need to bind a tenant to a specific source (IP range or domain)
- Ease of setting it up
You can use the following decision flow:

- Simple decision flow for choosing the tenant identification strategy
Choosing the right tenant location strategy
When choosing a tenant location (and registration strategy), you need to take into account these questions:
- Do you need to register new tenants dynamically?
- How much effort is acceptable for registering new tenants (e.g., changing some configuration file, recompiling the application, restarting it)?
- Are some aspects of tenants only configurable through configuration?
You need to weigh all of these constraints before you make a decision. The following picture summarizes this:

- Simple decision flow for choosing the tenant location strategy
Choosing the right data access strategy
The two APIs presented, NHibernate and Entity Framework, support all of the data access strategies. In the end, I think the decisive factor is the level of isolation that we want: separate databases offer the highest level, and data partitioning through discriminator columns offers the lowest. Criteria might include:
- Contractual requirements
- SLAs
- Regulatory demands
- Technical reasons
- Need to charge per used space

- Decision flow for selecting data separation strategy
As for the APIs themselves, there will be probably some benefit in terms of ease of use with Entity Framework, but it all goes down to what the developer knows best, although it’s true that having separate schemas is slightly trickier with NHibernate. In any case, using an ORM seems a wiser decision than sticking with plain ADO.NET, because of all of the additional services that ORMs provide. Using the Generic Repository pattern to abstract away the data access API might be a good idea only if you do not need any of the API-specific features, and just stick with the least common denominator.
Monitoring
Even if you do not use custom performance counters, the built-in ones offer great tools when it comes to monitoring—and perhaps, billing—individual tenants. Some performance counters offer good insights on what’s going on, tenant-wise (you can select the sites to monitor independently):
- ASP.NET Applications
- ASP.NET Apps v4.0.30319
- APP_POOL_WAS (application pool information)
You can view reports on some of these metrics, which can help you make decisions or serve as a billing basis:

- Reporting on performance counters
It is even possible to add alerts to be triggered when certain values exceed their normal thresholds:

- Adding a performance counter alert
This example shows a rule for generating an alert for when the Managed Memory Used (estimated) metric of the ASP.NET Applications counter exceeds 1,000,000, for the _LM_W3SVC_1_ROOT site (abc.com) which is evaluated every 15 seconds.
Layout
If you need to support different layouts per tenant, make sure you follow modern guidelines for defining the markup of your pages; namely, enforce a strict separation between content (HTML) and layout (CSS) and use the proper HTML elements for organizing your contents. For example, do not use the Table element for layout or grouping contents, because it does not scale well and imposes limitations on what we can change.
Note: The CSS Zen Garden site offers fantastic examples on the power of CSS.
- 1800+ high-performance UI components.
- Includes popular controls such as Grid, Chart, Scheduler, and more.
- 24x5 unlimited support by developers.