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();
});
Related
I've got an architecture issue that I'm hoping someone can be of assistance to guide me in a more ideal strategy. The way I've been forced to do this reeks of "code smell".
I've got two different kinds of "Roles". I've got the built in Identity Roles, and I've got a custom set of roles (User Group Roles). I store these User Group Roles in a database, essentially a relationship between a user id, a usergroup role id, and a usergroup id. I'm using Ninject for dependency injection of my UserGroupService that handles all the CRUD operations of assigning users with certain usergroup roles to usergroups.
My first plan of attack was to create a custom authorization attribute that I could place on actions, similar to the Identity [Authorize(Role="")] attribute. I did not have any luck with this because I cannot inject a service into an attribute class (needs a parameterless constructor).
After that didn't work, my second plan of attack was to write an extension method for IPrincipal, essentially mimicking User.IsInRole("") with User.IsInUserGroupRole(""). This didn't work because I cannot inject a service into a static class.
Currently I am stuck including some booleans in the model of every view that has role based logic involved. So for instance:
public ActionResult Navigation()
{
var isSystemAdmin = User.IsInRole("Administrator");
var isUserGroupAdmin = _userGroupService.IsUserGroupAdmin(User.Identity.GetUserId()) && !isSystemAdmin;
var isGeneralUser = !isSystemAdmin && !isUserGroupAdmin;
var model = new NavigationViewModel
{
IsSystemAdmin = isSystemAdmin,
IsUserGroupAdmin = isUserGroupAdmin,
IsGeneralUser = isGeneralUser
};
return PartialView("_Navigation", model);
}
The issue here is that I have to do this any time I want to determine what kind of roles the user is currently in. It works, but it smells.
Am I missing something here? I think the most ideal option would be the extension method strategy of being able to call it right off of User, but cannot seem to make that work.
Constructor DI is not the only way to get access to a dependency.
Each IOC has a way of resolving a dependency, all you need is a reference to the IOC container. So, even if your attribute requires a parameterless constructor you could still resolve the dependency manually.
Something like this should help :
http://www.c-sharpcorner.com/UploadFile/47fc0a/resolving-dependency-using-ninject/
Is it a great way to use your IOC this way? Probably not but it sure beats what you're doing now.
Given this code:
namespace Eisk.Controllers
{
public class EmployeesController : Controller
{
DatabaseContext _dbContext;
public EmployeesController(DatabaseContext databaseContext)
{
_dbContext = databaseContext;
}
public ViewResult Index()
{
var employees = _dbContext.EmployeeRepository;
return View(employees.ToArray());
}
Note that the constructor doesn't new up a database.
When accessed from a unit test I can inject a databaseContext and the controller will use that for the duration of the test. What I can't figure out is where this code is getting the database context it's using at run time. If I could find that out I might be able to figure out how to circumvent that behavior and have it use a mocked/in memory DB instead.
More explanation:
I don't have access to a legacy database for this application right now so I'm trying to Mock up an in memory data source that gets filled from xml files. That's why I need to be able to circumvent the default database context creation.
More Information:
Thanks for all the help so far you wonderful people you.
Steven seems to have directed me down the correct path.
In the Global.asax file is this call:
DependencyInjectorInitializer.Init();
Following that through the code I get to:
public static void Initialize()
{
_container = new UnityContainerFactory().CreateConfiguredContainer();
var serviceLocator = new UnityServiceLocator(_container);
ServiceLocator.SetLocatorProvider(() => serviceLocator);
DependencyResolver.SetResolver(new UnityDependencyResolver(_container));
}
At least that gets me headed in the right direction. Now I have to figure out how Unity is going about creating the context so I can do my intervention.
Let me plug the EISK MVC Employee Info Starter Kit here. It's a well thought out system developed by Mohammad Ashraful Alam Et al. that includes a well fledged example of how many of the new technologies fit together. MVC 5, Entity Framework 6, Unity, Authentication, OpenAuth, DI, Moq, and a couple of other things. Can be used as a template, general learning, or training.
Employee Info Starter Kit
With the default configuration of ASP.NET MVC, a controller should have a default constructor (i.e. a public constructor with no parameters). If not ASP.NET MVC will throw the following exception:
Type 'Eisk.Controllers.EmployeesController' does not have a default
constructor
If this however works, this means that you (or another developer) overwrote the default configuration by either using a custom IControllerFactory or custom IDependencyResolver. Most developers do this by using an open source Dependency Injection library (such as Simple Injector, Autofac or Castle Windsor). If you pull in the NuGet MVC integration packages for such library, it will usually do this configuration for you. So somebody on your team might have done this for you.
My advice is: talk to your team and ask them how they did this and which container they used and where you can find the configuration for that.
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
In CarTrackr project, It use some technique that creates only 1 repository instance for all request in Asp.net Mvc website and uses UnityControllerFactory class to manage all repository instanes(send to requested controller).
Is there any benefit to using single repository instance when compare with creating new repository instance every request?
I know, it may improve overall performance. But, Does it cause any transcation problem?
partial Global.asax
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
RegisterDependencies();
}
protected static void RegisterDependencies() {
IUnityContainer container = new UnityContainer();
// Registrations
container.RegisterType<IUserRepository, UserRepository>(new ContextLifetimeManager<IUserRepository>());
container.RegisterType<ICarRepository, CarRepository>(new ContextLifetimeManager<ICarRepository>());
// Set controller factory
ControllerBuilder.Current.SetControllerFactory(
new UnityControllerFactory(container)
);
}
}
partial CarController.cs
[Authorize]
public class CarController : Controller
{
private IUserRepository UserRepository;
private ICarRepository CarRepository;
public CarController(IUserRepository userRepository, ICarRepository carRepository)
{
UserRepository = userRepository;
CarRepository = carRepository;
}
}
Thanks,
Creating a repository instance per request by itself shouldn't cause any performance issue; the repository is often pretty shallow, and when it needs to access data things like connection pooling minimise the cost of establishing actual connections. Object creation is astonishingly cheap, especially for short-lived things like web requests where the object gets collected while still in "generation zero".
As to whether to have a single repository or a repository per instance - that depends on the repository ;-p
The biggest question is: is your repository thread safe? If not: one per request.
Even if it is though; if your repository itself keeps something like a LINQ-to-SQL DataContext (that you synchronize somehow), then you have big problems if you keep this long-term, in particular with the identity manager. You'll quickly use a lot of memory and get stale results. Far form ideal.
With a single repository instance, you will probably also end up with a lot of blocking trying to get thread safety. This can reduce throughput. Conversely, the database itself has good ways of achieving granular locks - which is particularly useful when you consider that often, concurrent requests will be looking at separate tables etc - so no blocking at the database layer. This would be very hard to do just at the repository layer - so you'd probably have to synchronize the entire "fetch" - very bad.
IMO, one per request is fine in most cases. If you want to cache data, do it separately - i.e. not directly on the repository instance.
I think you're misunderstanding whats happening with the ContextLifeTimeManager. By passing the manager into the Register() method your telling Unity to set the caching scope for your repository instance to HttpContext.
It is actually incorrect to say:
It use some technique that creates only 1 repository instance for all request in Asp.net > Mvc website
There is not a repository singleton. Unity is creating one for each request. It sounds like this is actually your desired behavior.
When the manager's scope is set to HttpContext the container looks to HttpContext for an existing instance of the requested type (in this case, your repository). Since the HttpContext is fresh on each request, the container will not have this instance, thus a new one will be created.
When you ask:
Is there any benefit to using single
repository instance when compare with
creating new repository instance every
request?
No.
As far as transaction problems: Threading will def be an issue. The CarRepository appears to be using Linq2Sql or Linq2Entities. Its ctor requires an active datacontext. DataContext is NOT thread safe. If the datacontext is being stored at a scope higher than the current request, there will be problems.
Using the new ContextLifetimeManager());, the lifetime of a repository is limited to one request. This means that evry request each repository is instantiated (if needed) and destroyed once a response has been sent to the client.
I am currently playing around with the HybridSessionBuilder class found on Jeffrey Palermo's blog post:
http://jeffreypalermo.com/blog/use-this-nhibernate-wrapper-to-keep-your-repository-classes-simple/
Using this class, my repository looks like this:
public class UserRepository : IUserRepository
{
private readonly ISessionBuilder _sessionBuilder;
public UserRepository(ISessionBuilder sessionBuilder)
{
_sessionBuilder = sessionBuilder;
}
public User GetByID(string userID)
{
using (ISession session = _sessionBuilder.GetSession())
{
return session.Get<User>(userID);
}
}
}
Is this the best way to go about managing the NHibernate session / factory? I've heard things about Unit of Work and creating a session per web request and flushing it at the end. From what I can tell, my current implementation isn't doing any of this. It is basically relying on the Repository to grab the session from the session factory and use it to run the queries.
Are there any pitfalls to doing database access this way?
You should not wrap your ISession in a using statement -- the point of passing the ISessionBuilder into the repository constructor (dependency injection) is that the calling code is responsible for controlling the life cycle of the ISession. By wrapping it in a using, Dispose() is called on the ISession and you won't be able to lazy load object members or persist it.
We do something similar by just passing in an ISession to the repository constructor. Mr. Palermo's code, as I understand it, simply adds lazy initialization of the ISession. I don't think that's needed because why would you new up a repository if you're not going to use it?
With ASP.Net MVC you want to make sure the life of the session is maintained during the Action method on your controller, as once your controller has exited all your data should be collected. I am not sure if this mechanism will help with that.
You might want to look into S#arp Architechure which is a set of libraries and guidance for building ASP.Net MVC application using nHibernate. http://code.google.com/p/sharp-architecture/
This is the setup I used after researching this more. Seems to work great and doesn't have that annoying habit of creating an ISession on static file requests like most guides out there:
http://www.kevinwilliampang.com/2010/04/06/setting-up-asp-net-mvc-with-fluent-nhibernate-and-structuremap/
I wouldn't open and close sessions on each data request to NHibernate. I would use the Unit of Work libraries that many others suggest or do some more reading. NHForge.org is getting started and I believe that there are some practices on setting up NHibernate for a general web application.
One of the "oh wow that's cool moments" that I've gotten from NHibernate was taking advantage of lazily loading collections during development. It was a neat experience being able to not have to do all those joins in order to display data on some associated object.
By closing the session like this, the above scenario would not be possible.
There might be something that is going on with transactions as well.
Just found a clean solution using Unity to inject a session per request:
http://letsfollowtheyellowbrickroad.blogspot.com/2010/05/nhibernate-sessions-in-aspnet-mvc.html