Managing multiple databases with NHibernate and Autofac - asp.net-mvc

I thought I'd get this question out there while I noodled on a solution on my own.
After having built out the bulk of an application, I have a last minute requirement to support reading/writing to an additional database (2 total, no known others). I built the application using NHibernate, with Autofac supplying the DI/IoC components. FWIW, this resides in an ASP.NET MVC 2 app.
I have a generic repository class that takes an NHibernate session. Theoretically, I can continue to use this generic repository (IRepository<>) for the second database so long as the session that gets passed to it is spawned from an appropriate SessionFactory, right?
Well, when the app starts, Autofac does it's thing. With regards to the Session and SessionFactory, I have a module that states:
builder.Register(c => c.Resolve<ISessionFactory>().OpenSession())
.InstancePerMatchingLifetimeScope(WebLifetime.Request)
.OnActivated(e =>
{
e.Context.Resolve<TransactionManager>().CurrentTransaction = ((ISession)e.Instance).BeginTransaction();
});
builder.Register(c => ConfigureNHibernate())
.SingleInstance();
where ConfigureNHibernate(), which returns the base SessionFactory, looks like:
private ISessionFactory ConfigureNHibernate()
{
Configuration cfg = new Configuration().Configure();
cfg.AddAssembly(typeof(Entity).Assembly);
return cfg.Configure().BuildSessionFactory();
}
Currently, this is limited to just the one database. In any other NHib scenario, I'd likely shove instances of the separate SessionFactories into a hash, and retrieve them as needed. I don't want to have to re-architect the whole thing as we're fairly close to a major release. So, I'm guessing I need to modify at least the methods above so that I can independently configure two SessionFactories. My gray area is how I'll go about specifying the correct Factory be used with a specific repository (or at least for entities specific to that second database).
Anyone have experience with this scenario while using an IoC container and NHibernate in this manner?
EDIT
I've stubbed out a GetSessionFactory method that takes a configuration file path, checks for the existance of a matching SessionFactory in the HttpRuntime.Cache, creates a new instance if one doesn't already exist, and returns that SessionFactory. Now I still need to hammer out how to tell Autofac how and when to specify an appropriate config path. The new method looks like (borrowed heavily from Billy's 2006 post here):
private ISessionFactory GetSessionFactory(string sessionFactoryConfigPath)
{
Configuration cfg = null;
var sessionFactory = (ISessionFactory)HttpRuntime.Cache.Get(sessionFactoryConfigPath);
if (sessionFactory == null)
{
if (!File.Exists(sessionFactoryConfigPath))
throw new FileNotFoundException("The nhibernate configuration file at '" + sessionFactoryConfigPath + "' could not be found.");
cfg = new Configuration().Configure(sessionFactoryConfigPath);
sessionFactory = cfg.BuildSessionFactory();
if (sessionFactory == null)
{
throw new Exception("cfg.BuildSessionFactory() returned null.");
}
HttpRuntime.Cache.Add(sessionFactoryConfigPath, sessionFactory, null, DateTime.Now.AddDays(7), TimeSpan.Zero, System.Web.Caching.CacheItemPriority.High, null);
}
return sessionFactory;
}

I'm assuming that you want different types of entities to go into each database; if you want to keep the same kinds of entities in each database, check out AutofacContrib.Multitenant.
The two ingredients that can help with this scenario are:
Named services http://code.google.com/p/autofac/wiki/TypedNamedAndKeyedServices
Resolved parameter http://code.google.com/p/autofac/wiki/ResolveParameters (minimal docs on this one - the coming Autofac 2.4 release has some syntax sweeteners around this...)
First, use named services to refer to the two different databases. I'll call them "db1" and "db2". All of the components relating to the database, all the way up to the session, get registered with a name:
builder.Register(c => ConfigureDb1())
.Named<ISessionFactory>("db1")
.SingleInstance();
builder.Register(c => c.ResolveNamed<ISessionFactory>("db1").OpenSession())
.Named<ISession>("db1")
.InstancePerLifetimeScope();
// Same for "db2" and so-on.
Now, assuming you have a type NHibernateRepository<T> that accepts an ISession as its constructor parameter, and that you can write a function WhichDatabase(Type entityType) that returns either "db1" or "db2" when given the type of an entity.
We use a ResolvedParameter to dynamically choose the session based on the entity type.
builder.RegisterGeneric(typeof(NHibernateRepository<>))
.As(typeof(IRepository<>))
.WithParameter(new ResolvedParameter(
(pi, c) => pi.ParameterType == typeof(ISession),
(pi, c) => c.ResolveNamed<ISession>(
WhichDatabase(pi.Member.DeclaringType.GetGenericArguments()[0])));
(Warning - compiled and tested in Google Chrome ;))
Now, resolving IRepository<MyEntity> will select the appropriate session, and sessions will continue to be lazily initialised and correctly disposed by Autofac.
You will have to think carefully about transaction management of course.
Hope this does the trick!
NB

Related

"An MVC filter provider has already been registered for a different Container instance." in Simple Injector 2.6

I previously had the setup for property injection in one of my attributes as
Container.RegisterInitializer<PermitAttribute>(initialize =>
{
initialize.QueryProcessor = Container.GetInstance<IQueryProcessor>();
});
And the usage was
public class PermitAttribute : ActionFilterAttribute
{
public IQueryProcessor QueryProcessor { get; set; }
}
but after updating to simpleinjector 2.6.1 The property injection broke. When I am trying to access QueryProcessor object inside PermitAttribute. It resolves null value where as the Simple Injector configuration still has the same property injection via delegate instance .
Is there any breaking change in property injection behavior due to which it was working in v2.5 and its not working anymore in 2.6.1 ?
Update 1:
The Line in the configuration was throwing error for MVC filter provider registration for attributes in v2.6.1
container.RegisterMvcIntegratedFilterProvider();
For that I commented it . And it stopped the property injection working . The property injection was inside one of my attributes . I guess that's the line above which affects it. And its throwing error in v2.6.1
Update 2:
Message
An MVC filter provider has already been registered for a different
Container instance. Registering MVC filter providers for different
containers is not supported by this method.
StackTrace :
at SimpleInjector.SimpleInjectorMvcExtensions.RequiresFilterProviderNotRegistered(Container container)
at SimpleInjector.SimpleInjectorMvcExtensions.RegisterMvcIntegratedFilterProvider(Container container)
at RemsPortal.App_Start.SimpleInjectorInitializer.Initialize() in d:\Projects Work\RemsPortal\V2.0 Web Portal\RemsPortal\App_Start\SimpleInjectorInitializer.cs:line 39
Update 3 :
entire Configuration
public static void Initialize()
{
var container = new Container();
InitializeContainer(container);
container.RegisterMvcIntegratedFilterProvider();
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
private static void InitializeContainer(Container Container)
{
Container.RegisterManyForOpenGeneric(typeof(IAsyncCommandHandler<,>),
AppDomain.CurrentDomain.GetAssemblies());
Container.RegisterOpenGeneric(typeof(ITransactionCommandHandler<,>),
typeof(TransactionCommandHandlerDecorator<,>));
Container.RegisterOpenGeneric(typeof(ICommandResult<>),
typeof(CommandHandlerResult<>));
Container.Register<ICommandResolver, CommandResolver>();
Container.Register<DbContext, RemsContext>();
Container.RegisterOpenGeneric(typeof(IPager<>), typeof(PagerModel<>));
//Container.RegisterPerWebRequest<DbContext, RemsContext>();
Container.Register<UserManager<Users, Guid>, RemsUserManager>();
Container.Register<RoleManager<Roles, Guid>, RemsRoleManager>();
Container.Register<IUserStore<Users, Guid>,
UserStore<Users, Roles, Guid, UserLogins, UserRoles, Claims>>();
Container.Register<IRoleStore<Roles, Guid>, RoleStore<Roles, Guid, UserRoles>>();
Container.RegisterManyForOpenGeneric(typeof(IAsyncQueryHandler<,>),
AppDomain.CurrentDomain.GetAssemblies());
Container.RegisterManyForOpenGeneric(typeof(IAsyncQueryHandler<>),
AppDomain.CurrentDomain.GetAssemblies());
Container.RegisterManyForOpenGeneric(typeof(IQueryHandler<,>),
AppDomain.CurrentDomain.GetAssemblies());
Container.RegisterOpenGeneric(typeof(IQueryResult<>), typeof(QueryResult<>));
Container.RegisterOpenGeneric(typeof(IPaginator<>), typeof(Paginator<>));
Container.Register<IPaginator, Paginator>();
Container.RegisterOpenGeneric(typeof(IAsyncQueryHandler<>), typeof(BaseQuery<>));
Container.RegisterOpenGeneric(typeof(IQueryHandler<>), typeof(BaseQuery<>));
Container.Register<IQueryProcessor, QueryProcessor>(Lifestyle.Singleton);
Container.Register<ILog, NLogger>(Lifestyle.Singleton);
Container.RegisterInitializer<PermitAttribute>(initialize =>
{
initialize.QueryProcessor = Container.GetInstance<IQueryProcessor>();
});
Container.RegisterInitializer<BaseController>(initialize =>
{
initialize.QueryProcessor = Container.GetInstance<IQueryProcessor>();
initialize.Logger = Container.GetInstance<ILog>();
});
Container.RegisterInitializer<BaseCommandHandler>(initialize =>
{
initialize.UserManager = Container.GetInstance<RemsUserManager>();
initialize.RoleManager = Container.GetInstance<RemsRoleManager>();
initialize.RemsContext = Container.GetInstance<RemsContext>();
initialize.QueryProcessor = Container.GetInstance<IQueryProcessor>();
});
Container.RegisterInitializer<BaseHandler>(initialize =>
{
initialize.UserManager = Container.GetInstance<RemsUserManager>();
initialize.RolesManager = Container.GetInstance<RemsRoleManager>();
});
}
The exception you are seeing is caused by a verification check that has been added to version 2.6 that prevents you from calling RegisterMvcAttributeFilterProvider and RegisterMvcIntegratedFilterProvider multiple times for different container instances. The problem is described in more details here.
The solution is to make sure RegisterMvcIntegratedFilterProvider is called only once in your code for the duration of the complete app domain and since RegisterMvcAttributeFilterProvider is deprecated, prevent having any calls at all to that legacy method. So if you only have one call in there, set a break point on this line, because you might be calling the Initialize() method twice!
The new RegisterMvcIntegratedFilterProvider allows complete integration of MVC attributes in the Simple Injector pipeline which makes sure that the RegisterInitializer method is called on attributes.
Another option though is to enable explicit property injection for attributes, or to fall back on the use of passive attributes as shown here.
But one note on property injection. I noticed you make extensive use of (explicit) property injection, especially for your base classes. From a design perspective however, it's better to remove the base classes all together, because they are a design smell at least, but might become maintenance problems later on. They might violate the Single Responsibility Principle or at least hide that derived types have too many dependencies, which often means too many responsibilities. I create quite big applications myself with MVC and command handlers and query handlers and I am always able to prevent the use of base classes. If a concrete handler needs a dependency, you should simply inject it into the constructor of that type. Prevent hiding that dependency by (ab)using a base type.
There is one important detail that you should be aware about when you use the RegisterMvcIntegratedFilterProvider. MVC caches filter attributes (god knows why) and this means that such attribute is basically becoming a singleton. This implies that every dependency this filter attribute has, becomes a singleton as well. This is of course be big problem if such dependency is not registered as singleton itself; it becomes a captive dependency. Although Simple Injector contains a diagnostic warning to detect these kinds of errors, Simple Injector will be unable to detect this with attributes, because attributes are not registered in the container. Because of this, my advice is to stay away from using property injection in your attributes at all. We are considering to deprecate the RegisterMvcIntegratedFilterProvider method from the MVC integration library.
As per steven It really was calling the container registration twice .
As I got to see tht
I had called SimpleinjectorInitializer.Initialize(); method in global.asax And then the webactivator also calling the same initizer was taking toll on the simpleinjector which caused the initization to fail for a check .
The solution to that is to remove SimpleinjectorInitializer.Initialize(); from the global.asax and let webactivator do its work .

NHibernate and contextual entities

I'm trying to use NHibernate for a new app with a legacy database. It's going pretty well but I'm stuck and can't find a good solution for a problem.
Let's say I have this model :
a Service table (Id, ServiceName..)
a Movie table (Id, Title, ...)
a Contents table which associates a service and a movie (IdContent, Name, IdMovie, IdService)
So I mapped this and it all went good. Now I can retrieve a movie, get all the contents associated, ...
My app is a movies shop "generator". Each "service" is in fact a different shop, when a user enter my website, he's redirected to one of the shops and obviously, I must show him only movies available for his shop. The idea is : user comes, his service is recognized, I present him movies which have contents linked to his service. I need to be able to retrieve all contents for a movie for the backoffice too.
I'm trying to find the most transparent way to accomplish this with NHibernate. I can't really make changes to the db model.
I thought about a few solutions :
Add the service condition into all my queries. Would work but it's a bit cumbersome. The model is very complex and has tons of tables/queries..
Use nhibernate filter. Seemed ideal and worked pretty good, I added the filter on serviceid in all my mappings and did the EnableFilter as soon as my user's service was recognized but.. nhibernate filtered collections don't work with 2nd lvl cache (redis in my case) and 2nd lvl cache usage is mandatory.
Add computed properties to my object like Movie.PublishedContents(Int32 serviceId). Probably would work but requires to write a lot of code and "pollutes" my domain.
Add new entities inheriting from my nhibernate entity like a PublishedMovie : Movie wich only presents the contextual data
None of these really satisfies me. Is there a good way to do this ?
Thanks !
You're asking about multi-tenancy with all the tenants in the same database. I've handled that scenario effectively using Ninject dependency injection. In my application the tenant is called "manual" and I'll use that in the sample code.
The route needs to contain the tenant e.g.
{manual}/{controller}/{action}/{id}
A constraint can be set on the tenant to limit the allowed tenants.
I use Ninject to configure and supply the ISessionFactory as a singleton and ISession in session-per-request strategy. This is encapsulated using Ninject Provider classes.
I do the filtering using lightweight repository classes, e.g.
public class ManualRepository
{
private readonly int _manualId;
private readonly ISession _session;
public ManualRepository(int manualId, ISession session)
{
_manualId = manualId;
_session = session;
}
public IQueryable<Manual> GetManual()
{
return _session.Query<Manual>().Where(m => m.ManualId == _manualId);
}
}
If you want pretty urls you'll need to translate the tenant route parameter into its corresponding database value. I have these set up in web.config and I load them into a dictionary at startup. An IRouteConstraint implementation reads the "manual" route value, looks it up, and sets the "manualId" route value.
Ninject can handle injecting the ISession into the repository and the repository into the controller. Any queries in the controller actions must be based on the repository method so that the filter is applied. The trick is injecting the manualId from the routing value. In NinjectWebCommon I have two methods to accomplish this:
private static int GetManualIdForRequest()
{
var httpContext = HttpContext.Current;
var routeValues = httpContext.Request.RequestContext.RouteData.Values;
if (routeValues.ContainsKey("manualId"))
{
return int.Parse(routeValues["manualId"].ToString());
}
const string msg = "Route does not contain 'manualId' required to construct object.";
throw new HttpException((int)HttpStatusCode.BadRequest, msg);
}
/// <summary>
/// Binding extension that injects the manualId from route data values to the ctor.
/// </summary>
private static void WithManualIdConstructor<T>(this IBindingWithSyntax<T> binding)
{
binding.WithConstructorArgument("manualId", context => GetManualIdForRequest());
}
And the repository bindings are declared to inject the manualId. There may be a better way to accomplish this through conventions.
kernel.Bind<ManualRepository>().ToSelf().WithManualIdConstructor();
The end result is that queries follow the pattern
var manual = _manualRepository
.GetManual()
.Where(m => m.EffectiveDate <= DateTime.Today)
.Select(m => new ManualView
{
ManualId = m.ManualId,
ManualName = m.Name
}).List();
and I don't need to worry about filtering per tenant in my queries.
As for the 2nd level cache, I don't use it in this app but my understanding is that you can set the cache region to segregate tenants. This should get you started: http://ayende.com/blog/1708/nhibernate-caching-the-secong-level-cache-space-is-shared

How to configure automapper for Unity dependency injection and Entity Framework in MVC 5 / Web API 2.0 app?

I'm using Automapper in my MVC 5 app to auto map my Entity Framework entities. Some of the mappings need to be looked up, so I need to inject them in the AutoMapperConfig. I use PerRequestLifetimeManager. To do the injection I've setup Unity in Appliction_BeginRequest the following lines:
Mapper.Initialize(cfg => cfg.ConstructServicesUsing(type => UnityConfig.GetConfiguredContainer().Resolve(type)));
var UnityContainer = UnityConfig.GetConfiguredContainer();
UnityContainer.Resolve<AutoMapperConfig>().MapAutoMapper();
But strangely after a few requests (hit F5 several times) the app breaks on Mapper.AssertConfigurationIsValid(); with the error message:
AutoMapper.AutoMapperConfigurationException was unhandled by user code
HResult=-2146233088 Message= Unmapped members were found. Review the
types and members below. Add a custom mapping expression, ignore, add
a custom resolver, or modify the source/destination type
======================================================================= IssueDTO -> Issue (Destination member list)
Improveize.Classes.DTO.IssueDTO -> Improveize.Classes.Persistent.Issue
(Destination member list)
----------------------------------------------------------------------- CreatedBy
But the member mentioned (CreatedBy) is mapped correctly in my code. FYI: the specific mapping makes use of a repository to lookup the data.
The relevant part of the AutoMapperConfig mapping that seems to generate the issue:
Mapper.CreateMap<IssueDTO, Issue>()
.ForMember(dest => dest.CreatedBy,
opt => opt.MapFrom(
src => _UserRepository.Get(u => u.UserID == src.CreatedByID).FirstOrDefault()));
So I thought this would have anything to do, that Automapper is initialized too often (every request) so I've put the Mapper.Initialize..... line in Application_Start.
But strangly (at least to me) I get the following error message when I want so save the data of a partial view through an Ajax call to the webapi part of the app.
The relationship between the two objects cannot be defined because
they are attached to different ObjectContext objects.
It breaks on the following lines in my DBContext when I want to set the EntityState to Modified:
public new virtual DbEntityEntry Entry(object obj)
{
return base.Entry(obj);
}
So apperantly the mapping resolved by a repository gets another DBContext. (if I ignore the properties that need a lookup, 'everything' works fine)
So it is Obvious that I'm doing something wrong, but I do not know what. The questions that arise:
where to put Mapper.Initialize(cfg => cfg.ConstructServicesUsing(type => UnityConfig.GetConfiguredContainer().Resolve(type))); ?? In which class to put in in?
can the context issue have anything to do with the web app is using MVC 5 and Webapi 2.0? Do they generate different dbcontext? And how can I avoid this.
where is the AutoMapper error coming from (it looks like the wrong message to me)? And how to solve
EDIT to answer the questions of Gert Arnold:
DbEntityEntry method breaks my DBContext
it breaks when I want to set the EntityState to Modified, called in the update action of the repository
Since I use PerRequestLifeTimeManager I assume the lifetime of _UserRepository.Get to be the lifespan of the request. I'm doing nothing explicitly to dispose the context nor the repository.
1) Mapper.AssertConfigurationIsValid(); is meant to be used in unit tests, not in production code.
2) Also this
Mapper.CreateMap<IssueDTO, Issue>()
.ForMember(dest => dest.CreatedBy,
opt => opt.MapFrom(
src => _UserRepository.Get(u => u.UserID ==src.CreatedByID).FirstOrDefault()));
is scary usage of Automapper. I never could imagine it could be abused this way. Violation of SRP in it's worst! Your mapping code does mapping AND does database lookup? mixing responsibilities here. Therefore you are going into lot of complexity with injecting Automapper configuration and other strange issues. Don't do it, keep it simple.
Let your controllers (or QueryHandlers) query database for entities and mapper just do it's job by mapping DB objects into view models.

MVC Conditional Dependency Injection

I am trying to figure out the best way to design an MVC4 application with DI via Ninject.
When the user comes to the system, they are presented with a login where they can select one of many databases. Each database is a separate catalog on a database server. What I need to do is inject a repository with the database connection details once the user is logged in. The type of repository does not change, just the connection details.
I have found this post which I could make work, but I am not sure if it is the best approach for my situation. What other options have people used with success?
Problem solved. As I am wishing to pass the connection string in the constructor for my concrete repository I can use the following Ninject WithConstructorArgument:
IBindingWithOrOnSyntax<T> WithConstructorArgument(string name, Func<Ninject.Activation.IContext, object> callback);
With this overload the callback is called every time an object is created. So my code looks like this and the MakeConnectionString method is called every time.
_Kernel = new StandardKernel();
_Kernel.Bind<ISomeItemRepository>().To<FakeSomeItemRepository>()
.WithConstructorArgument("connectionString", (c) =>
{
MakeConnectionString();
});

Unity constructor injection not resolving repositories as expected

I'm using Unity to resolve Mike Hadlow's implementation of generic repositories (linq to sql flavor) targeting multiple databases. The container configuration that works:
container.RegisterType<IConnectionStringProvider, HistoryConnectionProvider>(new TransientLifetimeManager())
.RegisterType<IConnectionStringProvider, MetaConnectionProvider>("meta", new TransientLifetimeManager())
.RegisterType<IDataContextProvider, DataContextProvider>(new TransientLifetimeManager())
.RegisterType<IDataContextProvider, DataContextProvider>("meta", new TransientLifetimeManager(), new InjectionConstructor(new ResolvedParameter<IConnectionStringProvider>("meta")))
// this registration of Repository<> resolves the history database by default
.RegisterType(typeof(IRepository<>), typeof(Repository<>), new TransientLifetimeManager());
// anything not targeting this database has to be declared
.RegisterType<IRepository<SpecificType>, Repository<SpecificType>>(new TransientLifetimeManager(), new InjectionConstructor(new ResolvedParameter<DataContextProvider>("meta")));
This seems unnecessarily verbose. So I'm currently trying different approaches. Using individual interfaces for each database:
IConnectionStringProvider historyConnectionProvider = new ConnectionProvider(connections.HistoryConnectionString);
IConnectionStringProvider metaConnectionProvider = new ConnectionProvider(connections.MetaConnectionString);
container.RegisterType<IDataContextProvider, DataContextProvider>("history", new TransientLifetimeManager(), new InjectionConstructor(historyConnectionProvider))
.RegisterType<IDataContextProvider, DataContextProvider>("meta", new TransientLifetimeManager(), new InjectionConstructor(metaConnectionProvider))
.RegisterType(typeof(IHistoryRepository<>), typeof(Repository<>), new TransientLifetimeManager(), new InjectionConstructor(new ResolvedParameter<IDataContextProvider>("history")))
.RegisterType(typeof(IMetaRepository<>), typeof(Repository<>), new TransientLifetimeManager(), new InjectionConstructor(new ResolvedParameter<IDataContextProvider>("meta")));
Unfortunately, this doesn't work. The result is the last type of IDataContextProvider registered getting injected into every type of Repository. Thanks in advance for any help.
Daniel, on the second set of code what is the purpose of naming the separate registrations? You already have decided to have separate interfaces for each database so there doesn't seem to be a need to have a name on it as well. I could be misunderstanding though. Moreover, in the second example, if Respository can fulfill the interface for both IMeta and IHistory, then it begs the question what is the difference between the two.
Had i given you example code how to achieve what you want, it would look very similar to the first example you had which in reality isn't all that much more verbose than the latter.
Solution to the original question
Unity needed a unique type, as well as interface. I'm still unsure as to why constructor injection didn't handle this. This works:
// where IMetaRepository<T> and MetaRepository<T> both are derived place holders
container.RegisterType(typeof(IMetaRepository<>), typeof(MetaRepository<>), new TransientLifetimeManager());
Unfortunately, this sets up a situation where consuming classes need knowledge of where their data is coming from, which I wasn't happy with.
Better Design
I wanted to leave my dbmls generated (so this ruled out making my models adhere to a certain interface), so I just threw them in different sub folders, causing the designer to generate a different namespace for each database.
Then, in my Repository implementation, I did the following:
public Repository(IConnections connections)
{
T type = new T();
var ns = type.GetType().Namespace;
if (ns == "Project.Common.DAL.History")
{
_dataContext = new DataContext(connections.HistoryConnectionString);
}
else if (ns == "Project.Common.DAL.Transaction")
{
_dataContext = new DataContext(connections.TransactionConnectionString);
}
else
{
_dataContext = new DataContext(connections.MetaConnectionString);
}
}
I think one step past this would be to build a custom type resolver for unity to check the namespace for me and return to injecting the data context (this will be necessary before unit of work can be implemented). I'm not going to mark this as the answer quite yet in case someone has a better solution.

Resources