Skip to content

Using MultiTenancyFramework with NHibernate and SimpleInjector

Somadina Mbadiwe edited this page Sep 11, 2016 · 5 revisions

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.

To register MVC features and settings

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;

Hooking Up SimpleInjector

To hook up SimpleInjector with the framework in an MVC5 project

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);

To hook up SimpleInjector with the framework in a Console or Windows Service project

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);

Authentication and Authorization Matters

To register the framework on OWIN with its UserManager and SignInManager

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>()
        )
    }
});

User Request Authorization

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 from CoreController. In it, override AreaName, 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 controller BaseController to your project. Let it inherit from CoreController. Then use it in all the places you would have used CoreController.

URL Routing

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!

Other Handy Features

  • 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")