Multi-Tenant w/ NHibernate+Castle Windsor (Single App, Multiple DBs) - asp.net-mvc

Creating a multi-tenant asp.net mvc 3 app with single app instance/multiple databases per tenant. There will also be a separate 'master' database that will house tenant-specific info (enabled features, tenant db connection info etc). Newbie to both NHibernate & IOC (Castle Windsor) and used this tutorial to get a basic CRUD setup going.
The following is what I use (from above-mentioned tutorial) to 'use' NHibernate:
public class PersistenceFacility : AbstractFacility
{
protected override void Init()
{
var config = BuildDatabaseConfiguration();
Kernel.Register(
Component.For<ISessionFactory>()
.UsingFactoryMethod(config.BuildSessionFactory),
Component.For<ISession>()
.UsingFactoryMethod(k => k.Resolve<ISessionFactory>().OpenSession())
.LifeStyle.PerWebRequest);
}
private Configuration BuildDatabaseConfiguration()
{
return Fluently.Configure()
.Database(SetupDatabase)
.Mappings(m =>
{
m.FluentMappings.AddFromAssemblyOf<SectionMap>()
.Conventions.AddFromAssemblyOf<TableNameConvention>();
})
.ExposeConfiguration(ConfigurePersistence)
.BuildConfiguration();
}
protected virtual AutoPersistenceModel CreateMappingModel()
{
var m = AutoMap.Assembly(typeof(EntityBase).Assembly)
.Where(IsDomainEntity)
.OverrideAll(ShouldIgnoreProperty)
.IgnoreBase<EntityBase>();
return m;
}
protected virtual IPersistenceConfigurer SetupDatabase()
{
return MsSqlConfiguration.MsSql2008
.DefaultSchema("dbo")
.UseOuterJoin()
.ProxyFactoryFactory(typeof(ProxyFactoryFactory))
.ConnectionString(x => x.FromConnectionStringWithKey("MasterDB"))
.ShowSql();
}
protected virtual void ConfigurePersistence(Configuration config)
{
SchemaMetadataUpdater.QuoteTableAndColumns(config);
}
protected virtual bool IsDomainEntity(Type t)
{
return typeof(EntityBase).IsAssignableFrom(t);
}
private void ShouldIgnoreProperty(IPropertyIgnorer property)
{
property.IgnoreProperties(p => p.MemberInfo.HasAttribute<DoNotMapAttribute>());
}
}
The approach I'm thinking of taking is that the application would look at the host header/url to determine the tenant and then query the 'master' db to get the respective tenant's database connection info. I'm guessing the approach I have to take is have a separate SessionFactory per client - only problem is I don't know how (and where) to integrate it. Would appreciate any help/pointers to get a better understanding of how to [a] resolve this problem [b] get a better understanding of how to use Castle Windsor. Apologies, as the castle site seems to be a great resource, but not easily understood by a newbie like me.
Thanks!
Environment: ASP.NET MVC 3, .NET 4, Castle Windsor + Fluent NHibernate + NHibernate (via NuGet)

usually the approach that's taken is to have multiple session factories (one per tenant) and use IHandlersSelector to pick the right one based on some data from the request.
Regarding the remark about documentation being not easily understood, we're keen to improve it if you'd like to point out parts that you found not too easy to follow.

Related

Set up Dependency Injection on Service Fabric using default ASP.NET Core DI container

I would like to use ASP.NET Core's default DI container to setup DI for my Service Fabric project.
//This is what I've got so far, and it works great
ServiceRuntime.RegisterServiceAsync(
"MyServiceType",
context => new MyService(context, new MyMonitor()
).GetAwaiter().GetResult();
//This is how I use it
public MyService(StatefulServiceContext context, IMonitor myMonitor)
: base(context)
{
this._myMonitor = myMonitor;
}
How would I set up DI, if MyMonitor class has a dependency on a ConfigProvider class, like this:
public MyMonitor(IConfigProvider configProvider)
{
this._configProvider = configProvider;
}
I think this question will give you some light: Why does ServiceRuntime.RegisterServiceAsync return before the serviceFactory func completes?
Technically, the ServiceRuntime.RegisterServiceAsync() is a dependency registration, it requires you to pass the serviceTypeName and the factory method responsible for creating the services Func<StatelessServiceContext, StatelessService> serviceFactory
The factory method receives the context and returns a service (Stateful or stateless).
For DI, you should register all dependencies in advance and call resolve services to create the constructor, something like:
var provider = new ServiceCollection()
.AddLogging()
.AddSingleton<IFooService, FooService>()
.AddSingleton<IMonitor, MyMonitor>()
.BuildServiceProvider();
ServiceRuntime.RegisterServiceAsync("MyServiceType",
context => new MyService(context, provider.GetService<IMonitor>());
}).GetAwaiter().GetResult();
PS:
Never Register the context (StatelessServiceContext\StatefulServiceContext) in the DI, in a shared process approach, multiple partitions might be hosted on same process and will have multiple contexts.
This code snippet is not tested, I've used in the past, don't have access to validate if matches the same code, but is very close to the approach used, might need some tweaks.
Hi #OscarCabreraRodríguez
I am working on the project that simplifies development of Service Fabric Reliable Services and it has great built-in support for dependency injection scenarios.
You can find general information project page, wiki and specific information about dependency injection here.
The idea is that project abstracts you from working with Service instance directly instead providing you with a set of more concrete objects.
Here is a simple example for ASP.NET Core application:
public static void Main(string[] args)
{
new HostBuilder()
.DefineStatefulService(
serviceBuilder =>
{
serviceBuilder
.UseServiceType("ServiceType")
.DefineAspNetCoreListener(
listenerBuilder =>
{
listenerBuilder
.UseEndpoint("ServiceEndpoint")
.UseUniqueServiceUrlIntegration()
.ConfigureWebHost(
webHostBuilder =>
{
webHostBuilder
.ConfigureServices(
services =>
{
// You can configure as usual.
services.AddTransient<IMyService, MyService>();
})
.UseStartup<Startup>();
});
});
})
.Build()
.Run();
[Route("api")]
public class ApiController : Controller
{
public ApiController(IMyService service) { }
[HttpGet]
[Route("value")]
public string GetValue()
{
return $"Value from {nameof(ApiController)}";
}
}
Hope I understand your use case correctly and this information is relevant.

Autofac, MVC (with ActionFilters), Web.Forms - dependency resolution conflict

I've got a legacy Web.Forms app that been partially rewritten to MVC. MVC part uses autofac as a dependency injection container.
MVC part have custom filter defined:
public class CustomActionFilter : ActionFilterAttribute
{
protected ILogger Logger { get; set; }
public CustomActionFilter(ILogger logger) { Logger = logger; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Logger.Log("OnActionExecuting");
}
}
It works fine when Web.Forms integration is disabled in web.config. Hovewer, when I try to use Web.Forms autofac integration, I've got the NullReferenceException related to AutofacFilterProvider somewhere in autofac internals (stack trace).
Global.asax.cs: http://pastebin.com/437Tnp0t
web.config: http://pastebin.com/5pU6SH6c
Note that CustomActionFilter is registered as global filter, thus it is registered with autofac:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(DependencyResolver.Current.GetService<CustomActionFilter>());
}
}
I've tried:
using separate containers for MVC and Web.Forms - same result
Use property injection instead of constructor - same result
Explicitly trigger dependencies resolution on web.forms pages (like this) - worked
So, the question is, are there any way to provide behind-the-scenes dependency resolution both to MVC and web.forms part. I'm new to autofac and somewhat new to dependency injection containers in general, so I might just miss something obvious.
Update: error has nothing to do with custom filters. If I remove all references to custom filters the bug behavior still the same, even the stack trace.
Actually there are two bugs? in Autofac which causing this behavior:
Bug #1: As side effect of the fix of Issue 351 the AutofacDependencyResolver needs to registered in the created Request bound LifeTimeScopes. The MVC intergration does this but the Winforms integration of course does not.
Bug? #2: Both the RequestLifetimeScopeProvider and the ContainerProvider stores the created ILifetimeScope with the same key HttpContext.Current.Items:
static ILifetimeScope LifetimeScope
{
get { return (ILifetimeScope)HttpContext.Current.Items[typeof(ILifetimeScope)]; }
set { HttpContext.Current.Items[typeof(ILifetimeScope)] = value; }
}
So there is a little bit race condition here because depending on which module gets executed first the WebForms or the MVC intergartion ILifetimeScope wins. So if the WebForms module wins the AutofacDependencyResolver won't be registered and you get the nice non descriptive exception.
Fix/workaround:
But there is an simple workaround: you just need to register the AutofacDependencyResolver in the ContainerProvider requestLifetimeConfiguration so no matter which one wins (WebForm vs. MVC) the AutofacDependencyResolver will be always registered:
var autofacDependencyResolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(autofacDependencyResolver);
_containerProvider = new ContainerProvider(container, requestContainerBuilder =>
requestContainerBuilder.RegisterInstance(autofacDependencyResolver)
.As<AutofacDependencyResolver>());

Multi-tenant ServiceStack API, same deployment to respond to requests on different hostnames?

We're creating APIs using ServiceStack that are multi-tenant. We want to do DNS-based load-balancing and routing, rather than stitch things up via a reverse proxy (like nginx or haproxy).
We have Request DTOs that have a Tenant parameter. ServiceStack (and its SwaggerFeature) allow us to define custom routes, and document the DTOs such that we can read values from path, query, headers, or body.
How do we (best) wire things so that DTO properties can read values from a hostname pattern as well? So, make the Route take values from matching out of the hostname as well as the path?
We'd like to have URLs like
https://{tenant}.{DNS zone for environment}/{rest of path with tokens}
Also - out DNS zone will vary depending which environment we're in - for non-production we use (say) testing-foobar.com, and production we use real-live.com. Ideally we'd be able to support both with a single route declaration (and we prefer decorating the Request DTO instead of imperative declaration at run-time AppHost.Init).
I solved this just this week, on a existing multi-tenant system which uses .NET security principals to deal with the user permissions and tenants. I used a custom ServiceRunner to select the tenant and set up the security. Your approach to multi-tenant is different, but using a ServiceRunner still seems a valid approach.
You'd end up with something like this:
public class MyServiceRunner<T> : ServiceRunner<T>
{
public MyServiceRunner(IAppHost appHost, ActionContext actionContext)
: base(appHost, actionContext)
{}
public override void BeforeEachRequest(IRequestContext requestContext, T request)
{
// Set backend authentication before the requests are processed.
if(request instanceof ITenantRequest)
{
Uri uri = new Uri(requestContext.AbsoluteUri);
string tenant = uri.Host; // Or whatever logic you need...
((ITenantRequest).Tenant = tenant;
}
}
}
public class MyAppHost : AppHostBase
{
public MyAppHost() : base("My Web Services", typeof(MyService).Assembly) { }
public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext actionContext)
{
return new MyServiceRunner<TRequest>(this, actionContext);
}
public override void Configure(Container container)
{
...
}
}
Perhaps the Requests filtering approach is somehow better, but this does the job for us.

Autofac Dependencies Per Area

I'm creating a new MVC4 site using Autoface that has a public consumer site as well as an admin area for managing the consumer facing site. The admin site will be located in a different area be using the same services as the consumer facing site, but will not having some of the custom branding features.
I've followed the advice given elsewhere of having a ViewDataFactory which provides a set of shared data for the view to use. My goal is to provide a different ViewDataFactory depending on what Area you are in.
So for example, here is the Service that implements IViewDataFactory
builder.RegisterType<SelfServiceViewDataFactory>().As<IViewDataFactory>();
This gives me one ViewFactory which is injected into all my controllers. However what I'm trying to acheive is something like this (not functional code):
builder.RegisterType<ViewDataFactory>().As<IViewDataFactory>().ForType(ControllerBase1);
builder.RegisterType<DifferentViewDataFactory>().As<IViewDataFactory>().ForType(ControllerBase2);
Where the controller type or the MVC area would determine which service is resolved.
EDIT
To clarify my post has two questions:
Is there a way in Autofac to say "only for classes of type X, a service of type Y will be provided by instance Z" ?
Is there a way to change the Autofac behavior based on the Area the component is being used in?
From everything I've been reading the answer to #1 seems to be "no" unless you have a parameter to use to check which component to supply. I know Ninject can supply a dependency based on namespace so other frameworks seems to handle this case. Seems the solution is to either supply a parameter or have two different services defined.
I haven't really seen much discussion of Autofac and MVC areas so I'm guessing #2 is also not possible without a custom solution. Thanks!
Using named services is probably your best option. So you'd do something like:
builder
.RegisterType<ViewDataFactory>()
.Named<IViewDataFactory>("Area1");
builder
.RegisterType<DifferentViewDataFactory>()
.As<IViewDataFactory>("Area2");
And then if you want to avoid having to then manually register your controllers. You could use this code that I just cobbled together and haven't tested:
Put this attribute somewhere globally accessible:
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
public class ServiceNamedAttribute : Attribute
{
private readonly string _key;
public ServiceNamedAttribute(string key)
{
_key = key;
}
public string Key { get { return _key; } }
}
Add this module to your Autofac config:
public class ServiceNamedModule : Module
{
protected override void AttachToComponentRegistration(
IComponentRegistry registry, IComponentRegistration registration)
{
registration.Preparing +=
(sender, args) =>
{
if (!(args.Component.Activator is ReflectionActivator))
return;
var namedParameter = new ResolvedParameter(
(p, c) => GetCustomAttribute<ServiceNamedAttribute>(p) != null,
(p, c) => c.ResolveNamed(GetCustomAttribute<ServiceNamedAttribute>(p).Name, p.ParameterType));
args.Parameters = args.Parameters.Union(new[] { namedParameter });
};
}
private static T GetCustomAttribute<T>(ParameterInfo parameter) where T : Attribute
{
return parameter.GetCustomAttributes(typeof(T), false).Cast<T>().SingleOrDefault();
}
}
And then you can still auto-register your controllers by decorating the constructor like so:
public class Controller1
{
public Controller1(ServiceNamed["Area1"] IViewDataFactory factory)
{ ... }
}

Extending Windows Authentication in ASP.NET MVC 3 Application

after a lot of googling and reading several solutions on how to manage mixed mode authentication in ASP.NET apps, I still have no fitting solution for my problem.
I've got to implement an intranet application for a bunch of different user groups. Until now i've used windows authenthication which was very simple to implement. My problems arise when it comes to authorizing usergroups for special application functionalities.
Using [Authorize(Users = "DOMAIN\\USER")] works great but due to that i have no access to the active directory managament, it is impossible to me to configure rolemanagement in the way I need it for my application.
What I'd like to do is defining custom roles and memberships in addition to the ones that are defined within the active directory (is such an extension possible? e.g. by implementing an own membershipprovider?).
What do you think is the best solution for my problem. Do I really have to implement a complex mixed mode authentication with forms authentication in addition to windows authentication?
Used Technologies:
MS SQL Server 2008
MS VS 2010
ASP.NET MVC 3 - Razor View Engine
Telerik Extensions for ASP.NET MVC
IIS 7 on Windows Server 2008
EDIT (final solution thanks to the help of dougajmcdonald):
After pointing me to use a custom IPrincipal implementation I've found some solutions here and here. Putting everything together I came to the following solution:
1.Create a custom principal implementation:
public class MyPrincipal: WindowsPrincipal
{
List<string> _roles;
public MyPrincipal(WindowsIdentity identity) : base(identity) {
// fill roles with a sample string just to test if it works
_roles = new List<string>{"someTestRole"};
// TODO: Get roles for the identity out of a custom DB table
}
public override bool IsInRole(string role)
{
if (base.IsInRole(role) || _roles.Contains(role))
{
return true;
}
else
{
return false;
}
}
}
2.Integrate my custom principal implementation into the application through extending the "Global.asax.cs" file:
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (Request.IsAuthenticated)
{
WindowsIdentity wi = (WindowsIdentity)HttpContext.Current.User.Identity;
MyPrincipal mp = new MyPrincipal(wi);
HttpContext.Current.User = mp;
}
}
3.Use my custom roles for authorization in my application
public class HomeController : Controller
{
[Authorize(Roles= "someTestRole")]
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
}
It works!!! yeah!
I'm not sure if this still applies in MVC, but in Webforms one way to do this would be as follows:
Create a new IPrincipal implementation perhaps extending WindowsPrincipal
In this class, give it a collection of roles (your own custom roles)
Populate those roles, by perhaps getting them from the DB.
Override IsInRole to return true if the role provided is EITHER true from the base call (WindowsAuthentication/Role) OR from your own custom role collection.
This way you can still hook into Principal.IsInRole("MyRole") and also the principal [PrincipalPermission()] annotation.
Hope it helps.
EDIT in answer to q's:
To integrate the principal into the authorisation you need to write your own method for OnAuthenticate in the global.asax for the type of authentication, so I would guess for you, something like this:
void WindowsAuthentication_OnAuthenticate(object sender, WindowsAuthenticationEventArgs e)
{
// ensure we have a name and made it through authentication
if (e.Identity != null && e.Identity.IsAuthenticated)
{
//create your principal, pass in the identity so you know what permissions are tied to
MyCustomePrincipal opPrincipal = new MyCustomePrincipal(e.Identity);
//assign your principal to the HttpContext.Current.User, or perhaps Thread.Current
HttpContext.Current.User = opPrincipal;
}
}
I believe Authorize came in at a later date to the PrincipalPermission, but I'm not too sure as to when/why of the differences I'm afraid :( - sorry!

Resources