DbContext lifetime beginning after user login - asp.net-mvc

Typically DbContext and ConnectionString are set at application start. In my ASP.NET MVC application I have a database with Users and ConnectionStrings data and depending on which user logs in, I want to use their ConnectionString to connect them to a secondary DbContext.
I tried to use DbContextScope but with the current implementation it doesn't seem to support this scenario. (I posted a related question for that here).
So in lifecycle of an ASP.NET MVC application how can we make sure the secondary DbContext is instantiated only after the user is logged in? What's the correct way to manage the lifecycle of DbContext here.
Thanks!

There is an overload for DbContext that takes in the connection string. With this, you could add a constructor to pass in the secondary connection string based upon the user that is accessing data.
public MySecondaryDbContext(string connectionString)
: base(connectionString)
{
}
Alternatively, you could pass in a user object that has the connection string to use.
public MySecondaryDbContext(UserObject user)
: base(user.ConnectionString)
{
}
Hope this helps you out.
Update for Lifecycle
As to the lifecycle, you could use something like this with a null check from the calling side.
public static MySecondaryDbContext GetContextForUser(UserObject user)
{
if(user.IsLoggedIn)
return null;
return new MySecondaryDbContext(user.ConnectionString);
}
private MySecondaryDbContext(string connectionString)
: base(connectionString)
{
}
This will prevent the secondary DbContext from being instantiated prior to the user being logged in.

Related

Dependency inject IPrincipal into a DBContext in separate assembly in 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();

Supply user specific dependencies to MVC controller with Ninject

I have some controllers that require a web service connection (an instance of MS Dynamics CRM CrmService) and I would like the controllers to receive this through their constructors. The CRM service has to be set up with a token that is based on who the currently logged in user is (when the user logs in the application authenticates against the CRM and can store the returned token in Session).
I'm not sure how best to supply this instance using Dependency Injection and Ninject. It seems a bit rubbish for the Ninject ToMethod() Func<> to access FormsAuth/Session for the current request (to obtain the token if authenticated) to create the appropriate instance. I'm also not sure what should happen if the user is not authenticated - I don't need these users be able to access the controller but the controller will be instantiated before any filters like [Authorize] will run so the dependency will always have to be met. From what I have read returning null is not ideal and I would have to change the Ninject configuration to do this anyway.
I was thinking that maybe the controller could get an instance of ICrmServiceFactory or something but that doesn't help me if the controllers end up having other dependencies which also rely on CrmService directly (and don't want to be passed a factory).
Any advice on how to solve this would be appreciated.
I usually set up a binding for IPrincipal:
kernel.Bind<IPrincipal>().ToMethod(c => HttpContext.Current.User);
Never really had a problem with this approach.
If I understand your question correctly then your controller has a dependency to CrmService and the CrmService requires some token stored in the session.
In that case you could inject a CrmTokenProvider to CrmService and add a property to that class which gets the value from the session whenever it is requested by the CrmService.
public class CrmService
{
public CrmService(CrmTokenProvider tokenProvider)
{
this.tokenProvider = tokenProvider;
}
public void DoSomeWork()
{
...
this.tokenProvider.Token;
...
}
}
I have ended up implementing this as follows:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<CrmService>()
.ToMethod(context =>
{
//return unauthenticated instance if user not logged in.
if (!HttpContext.Current.User.Identity.IsAuthenticated) return new CrmService();
return GetConnection(HttpContext.Current);
})
.InRequestScope();
}
private static CrmService GetConnection(HttpContext ctx)
{
//get stuff out of session and return service
}

Passing user information down to data access

I'm working on a desktop application that has generated code for database access and uses static objects for user identification.
Now we need to expose some of the logic by webservice and we are looking for the least intrusive form to push the user information down the pipe to the database access classes.
What we came up with was to pass a delegate to the Insert / Update methods that looks like this:
public delegate string GetLogin();
public class BaseEntity : BaseNotifiableEntity, System.ComponentModel.IDataErrorInfo
{
public GetLogin Login { get; set; }
(...)
}
public static class BaseEntityHelper
{
public static SqlCommand buildUpdateCommand(BaseEntity entity)
{
UpdateDefaultValues(entity, false);
(...)
}
public static void UpdateDefaultValues(BaseEntity entity, bool affectCreationFields)
{
if (entity.Login == null && AppServer.RunningApplication.CurrentUser == null)
throw new Exception("Something went wrong");
(...)
}
}
So in our logic will would have something like this:
public class Service
{
T_DIST_Service record;
(...)
public bool Update(DataAccess.Base.GetLogin login)
{
record.Login = login;
(...)
record.Update();
}
}
This of course involves changing a lot of methods in the application.
So i was wondering if there's a seamless way to accomplish this using dependency injection (for example).
Probably some of you have already go down this road and have some insights to share.
Thank you for your time.
EDIT 1:
Using .NET
On an architectural level it sounds like me that you are attempting to put logic in the data access layer that doesn't belong there. A data access component should be nothing but an anti-corruption layer, so any logic should ideally be implemented in the calling layer.
However, if you want a more immediate fix here and now, it would be most recommendable to use the built-in Thread.CurrentPrincipal Ambient Context.
If you have special information that your user object must carry around, you can use a custom implementation of IPrincipal to create a custom User Context.

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

ASP.NET MVC Session usage

Currently I am using ViewData or TempData for object persistance in my ASP.NET MVC application.
However in a few cases where I am storing objects into ViewData through my base controller class, I am hitting the database on every request (when ViewData["whatever"] == null).
It would be good to persist these into something with a longer lifespan, namely session. Similarly in an order processing pipeline, I don't want things like Order to be saved to the database on creation. I would rather populate the object in memory and then when the order gets to a certain state, save it.
So it would seem that session is the best place for this? Or would you recommend that in the case of order, to retrieve the order from the database on each request, rather than using session?
Thoughts, suggestions appreciated.
Thanks
Ben
Just thought I would share how I am using session in my application. I really like this implementation (Suggestions for Accessing ASP.NET MVC Session[] Data in Controllers and Extension Methods?) of using session as it makes it easy to swap out session for another store or for testing purposes.
Looking at the implementation it reminded me of the ObjectStore I have used in other projects to serialize objects as binary or xml and store in a database or on the filesystem.
I therefore simplified my interface (previously T had to be a class) and came up with the following:
public interface IObjectStore {
void Delete(string key);
T Get<T>(string key);
void Store<T>(string key, T value);
IList<T> GetList<T>(string key);
}
And my session store implementation:
public class SessionStore : IObjectStore
{
public void Delete(string key) {
HttpContext.Current.Session.Remove(key);
}
public T Get<T>(string key) {
return (T)HttpContext.Current.Session[key];
}
public void Store<T>(string key, T value) {
HttpContext.Current.Session[key] = value;
}
public IList<T> GetList<T>(string key) {
throw new NotImplementedException();
}
}
I then take in an IObjectStore in my base controller's constructor and can then use it like so to expose properties to my other controllers:
public string CurrentCustomer {
get {
string currentCustomer =
sessionStore.Get<string>(SessionKeys.CustomerSessionKey);
if (currentCustomer == null) {
currentCustomer = Guid.NewGuid().ToString();
sessionStore.Store<string>(SessionKeys.CustomerSessionKey, currentCustomer);
}
return currentCustomer;
}
}
Am quite pleased with this approach.
I believe this is what Session was designed for - to temporarily store session specific data.
However, due to increased complexity connected with using the Session, even if negligible - in my own ASP.NET MVC project, I have decided to hit the database on every Order creation step page (only ID is passed between the steps). I am ready to optimize and start using session as soon as I will see that the extra database hit for every request is a performance bottleneck.
You can serialize what you wish to persist and place it in a hidden input field like ViewState in WebForms.
Here's an article that should get you started: http://weblogs.asp.net/shijuvarghese/archive/2010/03/06/persisting-model-state-in-asp-net-mvc-using-html-serialize.aspx

Resources