-
Notifications
You must be signed in to change notification settings - Fork 6
Using MultiTenancyFramework with NHibernate and SimpleInjector
See the page in Getting Started for installation guide and architectural overview. This page discusses some of the usage issues and shows code samples of how to achieve basic stuffs.
In the Application_Start
method of Global.asax
, add the following piece of code
// Initialize MVC settings
AppStartInitializer.Initialize();
The above code registers all Areas, Routes and Filters; clears all view engines, leaving only Razor;
In the Application_Start
method of Global.asax
, add the following piece of code
//Required using statements
// using MultiTenancyFramework.SimpleInjector;
// using SimpleInjector;
// using SimpleInjector.Integration.Web;
// using SimpleInjector.Integration.Web.Mvc;
var container = new Container(); //SimpleInjector Container
// Simple Injector for MVC (nuget: SimpleInjector.Integration.Web.Mvc)
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.RegisterMvcIntegratedFilterProvider();
// other registrations you may wish to include.
// BaseContainer is from MultiTenancyFramework.SimpleInjector. It will do more registrations on the container,
// Particularly, it will find and register contract that follow the IService/Service convention.
var baseContainer = new BaseContainer(container: container);
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(baseContainer.Container));
// Very Important: This is what does the hooking up
MyServiceLocator.SetIoCContainer(baseContainer.Container);
In the Main
method, add the following piece of code
//Required using statements
// using MultiTenancyFramework.SimpleInjector;
// using SimpleInjector;
var container = new Container(); //SimpleInjector Container
// other registrations you may wish to include.
// BaseContainer is from MultiTenancyFramework.SimpleInjector. It will do more registrations on the container,
// Particularly, it will find and register contract that follow the IService/Service convention.
var baseContainer = new BaseContainer(container: container);
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(baseContainer.Container));
// Very Important: This is what does the hooking up
MyServiceLocator.SetIoCContainer(baseContainer.Container);
UserManager
and SigninManager
are used by MVC framework to handle user authentication. In the ConfigureAuth(IAppBuilder app)
method of Startup
class in the MVC5 project, remove whatever default code registering UserManager
and SignInManager
, and add the following piece of code
// You'll need to add the folllowing using statements
// using MultiTenancyFramework.Mvc.Identity;
// using MultiTenancyFramework.Entities;
// using MultiTenancyFramework;
//Tell your project you're using MultiTenancyFramework
var frameworkSettings = new MultiTenancyFrameworkSettings
{
//Set the properties you need to set. All have default values
};
app.UseMultiTenancyFramework(frameworkSettings);
//register UserManager and SignInManager
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>((x, y) =>
{
var mgr = ApplicationSignInManager.Create(x, y);
mgr.ValidateInstitution += inst =>
{
// provide further validation logic for tenants, if any. Note that this does not apply to the
// central institution administering the tenants. Currently, during sign-in, we check that the
// institution whose user is trying to sign in is
// * An actual institution on the system with valid institution code
// * Not disabled
// * Not deleted
// If your model is such that institutions need a valid subscription to access the system, here is the
// place to enforce such rules
return new InstitutionAccessValidationResult
{
AllowAccess = true, //or false, depending on your logic
Remarks = "More info", //if 'AllowAccess' is false, you'll need to tell the user why.
};
};
return mgr;
});
//And for the Cookie
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
ExpireTimeSpan = TimeSpan.FromMinutes(30),
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString(frameworkSettings.LoginPath), //"/Account/Login" is the default.
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, IdentityUser, long>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager), //from the framework
getUserIdCallback: (claimIdentity) => claimIdentity.GetUserId<long>()
)
}
});
From a coding point of view, all you need do is let your Controllers inherit from MultiTenancyFramework.Mvc.CoreController
. However, we recommend the following conventions:
- If you add an Area, say
MyArea
to your MVC project, then add a base controller in the area that inherits fromCoreController
. In it, overrideAreaName
, to return the your area name.
public abstract class MyAreaBaseController : CoreController
{
public override string AreaName
{
get
{
return "MyArea";
}
}
}
- If you have other things you want to handle centrally that we didn't include in
CoreController
, you can add an abstract base controllerBaseController
to your project. Let it inherit fromCoreController
. Then use it in all the places you would have usedCoreController
.
Routing will already be handled when you register MVC features and settings. However, when you add an Area (let's say the name of your area is MyArea
) to your project, you will need to make a little adjustment.
- Open the
MyAreaAreaRegistration
class generated - Replace the body of the
RegisterArea
method with the following line:
MultiTenancyFramework.Mvc.MvcUtility.RegisterArea(AreaName, context);
- That's all!
- We strongly recommend you follow the standard MVC convention in creating and naming views, actions and controller, in addition to the ones described above
- In any controller, if need be, you can set (change) the name of the folder holding the views through the
.ViewFolder
property. The default is the name of the controller. - In a controller, you can get the full url (path name) of a view and save MVC framework of the need to search several folders for the appropriate view given the name only. To do so, call the method
GetViewName("enterViewName")