Dependency inject IPrincipal into a DBContext in separate assembly in MVC - asp.net-mvc

I'm trying to get details about the current user in my DBContext so that I can store a CreatedByUserId and ModifiedByUserId when a record is updated.
What I'm finding is that the IPrincipal instance injected is valid for the controllers, but is null when injected into my DB Context, which is in a separate assembly.
I'm doing the injection with Autofac as follows:
builder.Register(c => HttpContext.Current.User).As<IPrincipal>().InstancePerRequest();
builder.Register<AppDbContext>(c => new AppDbContext(GlobalHost.DependencyResolver.Resolve<IPrincipal>())).InstancePerLifetimeScope();
My controller constructors look like this, and user will be valid here as expected:
public class ProductsController : Controller
{
private readonly IProductService _productService;
public ProductsController(IProductService productService, IPrincipal userPrincipal)
{
var user = userPrincipal;
_productService = productService;
}
My DBContext constructor looks like this and user will be null here:
public partial class AppDbContext : System.Data.Entity.DbContext, IAppDbContext
{
public AppDbContext(IPrincipal principal)
: this("Name=SqlConnection", principal)
{
var user = principal;
}
The controller code is called before the DB Context code, so it's not a timing issue, so I'm guessing the issue here is that the DB Context code is running on a different thread to the controller with different identity maybe?
If I use this code to get the identity in my DB context I can successfully get the user:
var user = System.Threading.Thread.CurrentPrincipal;
But it seems like I might run into issues getting the user in two different ways in the same app, and I'd need to figure out a way to make the DI return HTTPContext's user to the web project and the thread's principal to another assembly, all of which smacks of being the wrong solution?
Can anyone help me understand exactly why I'm seeing the behaviour above and advise on the best way to get the principal in the different assemblies of an mvc app?

So, the issue here turns out to be that I'm using the wrong Dependency Resolver when setting up the DB Context in this line:
builder.Register<AppDbContext>(c => new AppDbContext(GlobalHost.DependencyResolver.Resolve<IPrincipal>())).InstancePerLifetimeScope();
GlobalHost.DependencyResolver is giving me the SignalR resolver rather than MVC's resolver. Removing the GlobalHost bit then gives me the System.Web.MVC.DependencyResolver instead and then I can use that to get the IPrincipal as follows:
builder.Register<AppDbContext>(c => new AppDbContext(DependencyResolver.Current.GetService<IPrincipal>())).InstancePerRequest();

Related

How to use a single instance of DbContext , per request using Unity

I am refactoring a project that creates multiple DbCOntexts per method call in the data repositories.
So I want to have one instance of the DbContext per HTTP request.
I have tried to do:
container.RegisterType<ApplicationDbContext>(new PerRequestLifetimeManager());
and for every repository:
...
container.RegisterType<IBusinessRepository, BusinessRepository>(new InjectionConstructor(new ApplicationDbContext()));
container.RegisterType<ICountryRepository, CountryRepository>();
...
But that will create a new instance of the DbContext() per repository, of course.
I tried
container.RegisterType<IBranchCategoryRepository, BranchCategoryRepository>(
new InjectionConstructor(container.Resolve<ApplicationDbContext>()));
But that gives me:
The PerRequestLifetimeManager can only be used in the context of an
HTTP request. Possible causes for this error are using the lifetime
manager on a non-ASP.NET application, or using it in a thread that is
not associated with the appropriate synchronization context.
So how can I inject the same instance to each repository?
I'm not familiar with Unity, but i am with various other IoC frameworks.
Why are you trying to set what to inject on the repositories?
container.RegisterType<IBusinessRepository, BusinessRepository>(new InjectionConstructor(new ApplicationDbContext()));
Just leave out the DbContext here, but change it to:
container.RegisterType<IBusinessRepository, BusinessRepository>();
Because you did already register this component, it will be automatically injected in the constructor in each class that have a dependency. Your class should then look like this:
public class BusinessRepository : IBusinessRepository
{
private ApplicationDbContext _context;
public BusinessRepository(ApplicationDbContext context)
{
this._context = context
}
}
This works in Castle Windsor.

Controllers in ASP.NET MVC multitentant app (without subdomains)

I've read several articles about how to use subdomains and custom routes for multitenant applications, but the project I'm working on requires only one domain. We're using the default membership provider, and storing the encrypted tenant ID in the cookie.
My question regards the controllers. We're currently building them so that the first item in every action retrieves the TenantID from the cookie, and then passes that into every Linq query. Is it safe to move that to the top of the controller class instead, so it only happens once per controller instance? Or does that cause potential data crossover if multiple users are accessing the same controller?
I found this article which suggests that that's possible, but I want to be sure.
As an example, this is the current system:
public class ThisController : Controller
{
private DBContext db = new ThisContext();
public ActionResult Index()
{
long tenantid = AuthUser.GetTenantID();
...
This is what we're considering:
public class ThisController : Controller
{
private DBContext db = new ThisContext();
private Int64 tenantid = AuthUser.GetTenantID();
public ActionResult Index()
{
...
My understanding of the default behavior is that a new instance of the controller class is created with every request, but I want to be sure that's correct before we proceed.
Yes new instance of controller is indeed created by default for each request made to an mvc application. You can test it yourself by adding a constructor to the controller and doing Debug.WriteLine in the constructor.

ASP.NET MVC4 repository injection to controller that depends on currently logged user

Let's say I am creating a "TODO list" web application with following features:
have ability to register/login users
each user has it's own TODO list that is independent from other users
So I've created a simple model that has class ToDoItem.
I'd like to use good practices so I created a generic repository that should fetch TODO items from database:
public interface IRepository<T>
{
IQueryable<T> FindAll();
IQueryable<T> Find(Expression<Func<T, bool>> predicate);
void Add(T newEntity);
void Remove(T entity);
T FindById(long id);
}
(implementation is done with EF and code-first approach but that's not important right now)
This repository will be injected into controller that allows user to list, add, remove, edit TODO items. This is done via custom controller factory I've created that uses Ninject DI container to resolve repository interface to concrete implementation.
So the controller looks like this:
public class HomeController : Controller
{
IRepository<ToDoItem> _repository;
public HomeController(IRepository<ToDoItem> repository)
{
_repository = repository;
}
// list all TODO items for this user
[Authorize]
public ActionResult ListItems()
{
var todoItems = _repository.FindAll();
return View(todoItems);
}
}
My question what is the best way to make controller return TODO list only for the currently logged in user? Ideally I'd like to have controller work with repository that is injected and pre-set with the currently logged user. In other words I'd like to avoid this kind of code in action method:
// list all TODO items for this user
[Authorize]
public ActionResult ListItems()
{
var todoItems = _repository.FindAll(User.Identity);
return View(todoItems);
}
I was thinking that possible solution would be to make controller factory somehow know which user is logged so it would initialize concrete repository and set user ID so that controller doesn't have to do that in every action method. Would this be good approach and if so how can I implement it? If not, what are better alternatives?
I would tackle this in one of two ways:
1.
Make the lifestyle of the repository be per web request and take a dependency on the User.Identity such that this can be used inside of the repository methods. e.g.
public class Repository<ToDoItem> : IRepository<ToDoItem>
{
private IIdentity _identity;
// let the container inject the IIdentity into the repository
// (you will need to register a service with
// the container for IIdentity for this)
public Repository(IIdentity identity)
{
_identity = identity;
}
IQueryable<ToDoItem> FindAll()
{
return FromSomeContext().Where(x => x.Username == _identity.Name);
}
// ....
}
Then register a method with Ninject that it can call to resolve an IIdentity for any component that requires it. (You may decide that injecting an IPrincipal is more useful as you can get information about user roles with it too).
kernel.Bind<IIdentity>()
.ToMethod(ctx => HttpContext.Current.User.Identity)
.InRequestScope();
Now, assuming that Ninject is also constructing your controllers for you and you have registered components for the IRepository<T> services that your application requires, The current user IIdentity will be injected into the Repository<ToDoItem> for you by Ninject.
2.
Create an extension method for IRepository<ToDoItem> (or even IRepository<T> if appropriate) that wraps adding the Where() expression for limiting the returned TODO items only to those that are relevant to the current user.
For those, who use Windsor Castle:
container.Register(
...
Component.For<IIdentity>()
.UsingFactoryMethod(() => { return HttpContext.Current.User.Identity; })
.LifeStyle.PerWebRequest,
...);
Note:
Component.For<ICustomer>().Instance(HttpContext.Current.User.Identity)
does not work, because "When you register an existing instance, even if you specify a lifestyle it will be ignored.", see Windsor Castle Documentation

Injecting an IPrincipal with Unity Property Injection at runtime

Using Unity in an ASP.Net MVC 2 app I have various dependencies on Controllers instantiated correctly. However, I want to ensure that the current IPrincipal for the user is going to be passed via injection to lower level Services, Repository etc.
Therefore in a lower level service I have something like:
[Dependency] IPrincipal CurrentUser {get; set;}
If I use Property Dependency Injection I do not get what I want because the Controller is instantiated BEFORE a User principal is available and in any case Unity does not know to get the current user credentials.
So what I want is to be able to inject the current user's IPrincipal (or probably RolePrincipal) into one of the dependencies for the Controller.
How can I do this?
Why not take the direct route, and just assign it.
Thread.CurrentPrincipal = user;
Dependency injection is good, but don't let it get in the way of the best dependency injector, the programmer.
While this thread is old, it looks like Jon Kruger has an answer that seems to directly answer the original question: http://jonkruger.com/blog/2009/04/13/hiding-threadcurrentprincipal-from-your-code/
Why inject it? The current principal is already present as User. That is what we use, and it works fine so far. The user shouldn't change within a single request, should it?
protected void Application_AuthenticateRequest()
{
var ticket = GetAuthenticationTicket();
// Perform actual authentication, etc.
MyUser user = BigAuthStuff();
Context.User = user;
Thread.CurrentPrincipal = user;
}
public class MyBaseController : Controller
{
protected MyUser AuthenticatedUser
{
get { return User as MyUser; }
}
}

Why is my DataContext null in only one action?

I have a property on my BaseController called DataContext that holds my LINQ to SQL data context (or fake context for testing). When using a parameterless constructor (in other words, when a request to ASP.NET MVC is made), a new instance of my LINQ to SQL data context is assigned to the property:
public class BaseController : Controller {
public IDataContextWrapper DataContext { get; set; }
public BaseController() : this(new DataContextWrapper<MyDataContext>()) { }
public BaseController(IDataContextWrapper context) {
DataContext = context;
}
}
Also in my BaseController, I set some global ViewData items:
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
ViewData["Example"] = DataContext.Table<Example>().Count();
base.OnActionExecuting(filterContext);
}
This is working fine for almost every action. The only one that doesn't work is the Logout action on my AccountController:
public ActionResult Logout() {
FormsAuth.SignOut();
return RedirectToResult("Login");
}
This raises a NullReferenceException during BaseController.OnActionExecuting. When executing that particular action, the DataContext property is null.
Why would this only occur on one action?
Note: IDataContextWrapper and DataContextWrapper simply wraps the existing functionality of the LINQ to SQL DataContext object so that it can be replaced with a fake context in unit tests. It doesn't do any disposing on its own, but leaves it up to the underlying DataContext, so I'm pretty certain that's not the problem.
To follow up my comment, check out this link and more specifically the link Microsoft documentation here which state:
In general, a DataContext instance is designed to last for one "unit of work" however your application defines that term. A DataContext is lightweight and is not expensive to create. A typical LINQ to SQL application creates DataContext instances at method scope or as a member of short-lived classes that represent a logical set of related database operations.
Microsoft did a terrible job explaining this and frankly explaining using Linq in an n-tier environment in the first place. In my particular case, I had one (static) datacontext implemented via Singleton pattern, which I am guessing is what you have done as well. ( As it is the most logical design, IMHO ). This however, is extremely NOT the way to do things. In my case, the fix was actually pretty easy, changing my GetDataContext() call to return a new DataContext every time, instead of returning the static instance. This however, you will find, creates a whole new crop of problems. None of them are insurmountable once you figure them out, but definitely a pain.
If you have such a setup ( Singleton accessors for your DataContext), change it to see if it fixes your problem.
Regardless, do not use a global DataContext, nor persist a DataContext if dealing with an n-tier architecture.
Even if this doesn't solve your particular problem, I highly suggest you re-architect your solution to make DataContexts have a unit of work lifespan, if it hasn't bitten you already, it will.
For reasons that I don't quite understand, when a new AccountController is created for the Logout action, ASP.NET MVC is using the second constructor with a null parameter (could be a bug?). I changed the class to create a new default DataContext when the parameter is null:
public class BaseController : Controller {
public IDataContextWrapper DataContext { get; set; }
public BaseController() : this(null) { }
public BaseController(IDataContextWrapper context) {
DataContext = dataContext ?? new DataContextWrapper<MyDataContext>();
}
}
Now it works.
It strikes me as strange that ASP.NET MVC used the default constructor in some cases, and an overload in others, though. Can anyone shed some light on this?

Resources