Unity MVC injecting current user - asp.net-mvc

I am using the basic Unity MVC Nuget Bootstrapper.
I would like to Inject the currently logged in user into the services I am defining
_container.RegisterType<IDoSomethingService, DoSomethingService>();
such that DoSomethingService gets an ICurrentUser object or some form of resolver.
I am trying to avoid having to make calls like
DoSomethingService.DoSomething(currentUserUsingService,...);
Or in the constructor of all the MVC Controllers also avoiding setting:
DoSomethingService.CurrentUSer = User.Identity.Name;

In my projects I use next:
public interface ICurrentUserService
{
int? GetId();
}
I register next implementation:
public class CurrentUserService: ICurrentUserService
{
public int? GetId()
{
if (!HttpContext.Current.User.Identity.IsAuthenticated)
return null;
return int.Parse(HttpContext.Current.User.Identity.Name);//When auth - id stored in cookie
}
}
_container.RegisterType<ICurrentUserService, CurrentUserService>();
And make my services depends on ICurrentUserService (by using ctor parameter) or pass userId into methods of my services in controllers.

Related

Configure Unity container per-request in OWIN middleware

I'm wanting to configure registrations in a Unity container being used by ASP.NET Web API 2 based on properties of a HTTP request. For example, a request to /api/database1/values should result in a Unity container configuration with an IDbContext configured for database1, while a request to /api/database4/values will get an IDbContext configured for database4.
I've gotten so far as using UnityHierarchicalDependencyResolver as the dependency resolver, so types registered with HierarchicalLifetimeManager last only for the lifetime of the request. This works well for getting types resolved per request. But how to get them registered per request using OWIN middleware is beyond me.
In my middleware, a call to System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IUnityContainer)) gets an instance of IUnityContainer, but it's the same container for all requests, including any registrations from previous requests.
By encapsulating UnityHierarchicalDependencyResolver with my own implementation of IDependencyResolver I can see that IDependencyResolver.BeginScope isn't called until much later in the process. So the problem would seem to be that the child container isn't created until Web API wakes up, long after my middleware calls Next(..).
Is there a way I can get the scope of my dependency resolver to start sooner? Is there some other strategy that I'm missing. In case it makes any difference, I'm hosting in IIS, but favouring the OWIN middleware approach.
Update
This isn't an answer, and it's too big for a comment, but after struggling to solve this with Unity I decided to switch to Autofac and it all just fell into place.
The Autofac OWIN packages (Autofac.Mvc5.Owin, Autofac.Owin, Autofac.WebApi2.Owin) make it dead easy to use Autofac within the OWIN pipeline and ensure appropriate lifetime management in ASP.NET MVC and Web API. This was the missing link.
I couldn't find a way to reconfigure the container per-request, but it did at least make it possible to configure a factory per-request (so yes, #Haukinger and #alltej, you were right to push in that direction.
So I register a factory like:
builder.RegisterType<DataDependencyFactory>().InstancePerRequest();
And register the create method of that factory like:
builder
.Register(c => c.Resolve<DataDependencyFactory>().CreateDataDependency())
.As<IDataDependency>()
.InstancePerRequest();
Registering the factory this way is particularly useful, because downstream dependents don't need to be aware of the factory. I like this because my dependents don't need a factory, they need an instance. The container bends to the needs of my dependents, not the other way around :)
Then, in a piece of OWIN middleware, I resolve the factory, and set a property on it according to the properties of the request. Subsequent resolution of IDataDependency in an MVC or Web API controller, or anything else later in the OWIN pipeline, will get an instance configured according to the property on the factory.
Based on your api URL ("/api/database4/values"), I suggest that you create a filter attribute(e.g. DbIdFilter) so that you can reuse the filter attribute to other controller methods that follow similar url path/segment like this below:
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/values")]
public IHttpActionResult GetValues()
{
return Ok();
}
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/products")]
public IHttpActionResult GetProducts()
{
return Ok();
}
First, create the filter attribute:
public class DbIdFilterAttribute : ActionFilterAttribute
{
private readonly string _routeDataId;
private const string defaultRouteName = "databaseId";
public DbIdFilterAttribute():this(defaultRouteName)
{}
public DbIdFilterAttribute(string routeDataId)
{
_routeDataId = routeDataId;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
var routeData = actionContext.Request.GetRouteData();
var dbId = routeData.Values[_routeDataId] as string;
//here we create the db instance at the filter level.
DbInstanceFactory.RegisterDbInstance(dbId);
}
}
Next, create an instance factory that will register/resolve the db instance during runtime:
public class DbInstanceFactory : IDbInstanceFactory
{
public static IDbInstance RegisterDbInstance(string databaseId)
{
var factory = UnityConfig.GetConfiguredContainer().Resolve<IDbInstanceFactory>();
return factory.CreateInstance(databaseId);
}
public IDbInstance CreateInstance(string databaseId)
{
var container = UnityConfig.GetConfiguredContainer();
//container.RegisterType<IDbInstance, DbInstance>();
container.RegisterType<IDbInstance, DbInstance>(new InjectionConstructor(databaseId));
var dbInstance = container.Resolve<IDbInstance>();
return dbInstance;
}
public IDbInstance GetInstance()
{
var container = UnityConfig.GetConfiguredContainer();
var dbInstance = container.Resolve<IDbInstance>();
return dbInstance;
}
}
public interface IDbInstanceFactory
{
IDbInstance CreateInstance(string databaseId);
IDbInstance GetInstance();
}
Register this factory class in UnityConfig.cs (or wherever you currently register the types):
container.RegisterType<IDbInstanceFactory, DbInstanceFactory>
(new ContainerControlledLifetimeManager());
It's registered ContainerControlledLifetimeManager since this factory does not have to be a per request.
So just a basic DbInstance class below(for clarity) that takes a parameter in the constructor (this parameter can be your connection string or a named connection):
public class DbInstance : IDbInstance
{
public string DbId { get; }
public DbInstance(string databaseId)
{
DbId = databaseId;
}
}
public interface IDbInstance
{
string DbId { get; }
}
In controller class, you can use it like this:
....
private IDbInstanceFactory _dbFactory;
public MyController(IDbInstanceFactory dbFactory)
{
_dbFactory = dbFactory;
}
// Alternate, if you want to use property injection instead of constructor injection
//[Dependency]
//public IDbInstanceFactory DbFactory { get; set; }
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/test")]
public IHttpActionResult Test()
{
var db = _dbFactory.GetInstance();
return Ok(db.DbId);
}
...

ASP.Net Core Call a controller from another controller

In my ASP.Net Core MVC 6 solution I have two sets of controllers. One set contains the webpages with their regular views. Another set contains the API controllers.
To avoid duplicating db logic the web controllers are using the API controllers. Currently I am creating an instance of the required controller manually by handing it a DbContext as constructor argument. This is the DbContext given to web controller by dependency injection.
But whenever I add another constructor parameter to the API controller I need to modify all web controllers that use this API controller.
How can I use the dependency injection system builtin to ASP.Net 5 to create an instance of the required API controller for me? Then it would fill in the required constructor parameters automatically.
One solution could be to move the db logic from the API controllers to a separate layer and call that from both API and web controllers. This would not solve my problem since the new layer would still need the same parameters and I'm not fan of the unnecessary wiring.
Another solution would be to have the web controllers access the API through a web call, but that just adds complexity to the app.
Today I am doing this:
public IActionResult Index()
{
using (var foobarController = new Areas.Api.Controllers.FoobarController(
// All of these has to be in the constructor of this controller so they can be passed on to the ctor of api controller
_dbContext, _appEnvironment,
_userManager, _roleManager,
_emailSender, _smsSender))
{
var model = new IndexViewModel();
model.Foo = foobarController.List(new FoobarRequest() { Foo = true, Bar = false });
model.Bar = foobarController.List(new FoobarRequest() { Foo = false, Bar = true });
return View(model);
}
}
And I am hoping for something like this:
(This example does not work.)
using (var foobarController = CallContextServiceLocator.Locator.ServiceProvider.GetService<Areas.Api.Controllers.FoobarController>())
{
var model = new IndexViewModel();
model.Foo = foobarController.List(new FoobarRequest() { Foo = true, Bar = false });
model.Bar = foobarController.List(new FoobarRequest() { Foo = false, Bar = true });
return View(model);
}
How can I use the dependency injection system builtin to ASP.Net 5 to create an instance of the required API controller for me?
In your Startup.cs can tell the MVC to register all your controllers as services.
services.AddMvc().AddControllersAsServices();
Then you can simply inject the desired controller in your other controller via the DI mechanism and invoke its action method.
Don't do it. Move that logic to another component that gets shared between the 2 controllers. The controller is dispatched to by the framework as a result of an HTTP call, its not your public API surface. In general, your controllers should be used as a the place where the HTTP request is transformed into business objects. Operations on those objects should be delegate to another layer (especially if it needs to be used from more than one place in your application).
To be able to use a controller from another controller you need to:
Register the controller in Startup.cs ConfigureServices: services.AddTransient <Areas.Api.Controllers.FoobarController, Areas.Api.Controllers.FoobarController>();
You must pass the controller you want to access as a ctor parameter into the main controller.
If you need to access local properties in the controller such as User or Url there are two ways to do this.
The first way is to use DI to get an instance of IHttpContextAccessor to access User and IUrlHelper to access Url objects:
public class FoobarController : Controller
{
private readonly ApplicationDbContext _dbContext;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IUrlHelper _urlHelper;
public FoobarController(ApplicationDbContext dbContext, IHttpContextAccessor httpContextAccessor, IUrlHelper _urlHelper, [...])
{
_dbContext = dbContext;
_httpContextAccessor = httpContextAccessor;
_urlHelper = urlHelper;
}
public FoobarResponse List(FoobarRequest request)
{
var userId = _httpContextAccessor.HttpContext.User.GetUserId();
var response = new FoobarResponse();
response.List = _dbContext.Foobars.Where(f => f.UserId == userId).ToList();
response.Thumb =
return response;
}
}
The second way is to set it in the calling controller:
public class HomeController : Controller
{
private Areas.Api.Controllers.FoobarController _foobarController;
public HomeController(Areas.Api.Controllers.FoobarController foobarController)
{
_foobarController = foobarController;
}
private void InitControllers()
{
// We can't set this at Ctor because we don't have our local copy yet
// Access to Url
_foobarController.Url = Url;
// Access to User
_foobarController.ActionContext = ActionContext;
// For more references see https://github.com/aspnet/Mvc/blob/6.0.0-rc1/src/Microsoft.AspNet.Mvc.ViewFeatures/Controller.cs
// Note: This will change in RC2
}
public IActionResult Index()
{
InitControllers();
var model = new IndexViewModel();
model.Foo = _foobarController.List(new FoobarRequest() { Foo = true, Bar = false });
model.Bar = _foobarController.List(new FoobarRequest() { Foo = false, Bar = true });
return View(model);
}
}
The source code for ASP.Net Core MVC6 RC1 Controller can be found here. It is however undergoing heavy rewrite for RC2 and with it the properties that has to be copied to get access to User and Url will change.
#B12Toaster is correct for MVC but if you only use ApiController you should do it like this:
services.AddControllers().AddControllersAsServices();
Why would your new layer need wiring up? Why not take in an object into both controllers and call a method on that object. The DI container could resolve the dependencies of this new object without duplicated wiring couldn't it?
ie you could have this:
public class MvcController
{
SharedComponent sharedComponent;
public MvcController(SharedComponent sharedComponent)
{
this.sharedComponent = sharedComponent;
}
public IActionResult Index()
{
var model = new IndexViewModel();
model.Foo = shredComponent.List(new FoobarRequest() { Foo = true, Bar = false });
model.Bar = shredComponent.List(new FoobarRequest() { Foo = false, Bar = true });
return View(model);
}
}
//Repeat this for the API controller
public class SharedComponent
{
public SharedComponent(DBContext dbContext, AppEnvironment appEnvironment, UserManager userManager, RoleManager roleManager,
EmailSender emailSender, SmsSender smsSender)
{
...Store in fields for later usage
}
}
I'd have to agree with others that injecting the controller may not be the best route. Mostly because it marries the business logic with ASP.Net instead of treating it like an IO device like, in my opinion, it should be.
Let's say we have an interface that looks like this:
public interface ICalculator {
int Add(int left, int right);
}
and we have an implementation that stores the business logic:
public class MyCalculator : ICalculator {
public int Add(int left, int right) => left + right;
}
This implementation can be used as a background service, within the same process as a WPF application, or as an ASP.NET WebAPI controller. It would look something like this:
[ApiController]
[Route("api/{controller}")]
public void CalculatorController : Controller, ICalculator {
private readonly ICalculator _calculator;
public CalculatorController(ICalculator calc) => _calculator = calc;
[Route("Add")]
public int Add(int left, int right) => _calculator.Add(left, right);
}
If that controller has a dependency on a repository you can inject that interface too. Personally I like defining a collection of repositories (like IUserRepository for example) and injecting only what is needed instead of the entire DbContext.
public CalculatorController(ICalculator calculator, IDbContext db) { }
There's nothing wrong with a controller depending on more than just the thing it is decorating. Just make sure you have a set of tests that assert various things. For example you could assert that when a particular controller method is called the particular method on the other interface is also called.
Personally I find this approach a better fit. It's okay to use certain technologies but they should be kept at arm's length from the business rules. A developer should be able to take the business rules that govern a particular part of the code and switch from a WCF service to ASP.NET WebAPI trivially.
I've personally been a part of a couple projects where we had to switch from one database technology to another (SQL Server to CouchDB) and one where our micro-services needed to be running as restful Web API services instead of Windows services. If you architect things this way those types of projects become relatively trivial compared to how things are normally composed.

How to use a Session provider in a DI project

I am developing a web application in ASP.NET MVC5.
Like all basic web applications it also has a login page where a user can authenticate himself. Once authenticated I want to store a couple of user-related items in the Session so I don't have to query the database every time to reconstruct the authenticated user.
After having read Mark Seemann's book about Dependency Injection I want to loosely couple all my layers and make sure that everything can easily be replaced.
At the moment my SessionProvider is by default using the Session object, but maybe in the future this could change to another type of storage mechanism.
The approach I have taken is by using Ambient Context which he explained with the TimeProvider example, but I am wondering if this is the right approach for this functionality and if it is thread safe (also for unit testing).
Is my solution proper or how would you implement such a mechanism? This has been in my head for days now so who can help me define the best solution?
Thanks!
public abstract class SessionProvider
{
private static SessionProvider _current;
static SessionProvider()
{
_current = new DefaultSessionProvider();
}
public static SessionProvider Current
{
get { return _current; }
set
{
if (value == null)
{
throw new ArgumentNullException();
}
_current = value;
}
}
public abstract string UserName { get; set; }
}
My local default:
public class DefaultSessionProvider : SessionProvider
{
public override string UserName
{
get { return (string) HttpContext.Current.Session["username"]; }
set { HttpContext.Current.Session["username"] = value; }
}
}
So I have access in my entire solution to my SessionProvider, whether this is a real session object or a database-driven storage mechanism...
SessionProvider.Current.UserName = "myUserName";
Once authenticated I want to store a couple of user-related items in
the Session so I don't have to query the database every time to
reconstruct the authenticated user.
Well, it looks like you're working on some sort of caching mechanism. It doesn't really matter if it's in a Session or in Redis cache, or any other type of cache. And this cache is key-value storage. I would create cache interface, something like that:
interface ICache
{
object this[string key] {get; set;}
}
And create concrete classes. SessionCache in your case:
public SessionCache : ICache
{
private IHttpSessionState _session;
public SessionCache(IHttpSessionState session)
{
_session = session;
}
// ICache implementation goes here...
}
So you'll narrow down the problem to dependency-inject Session object to concrete class (SessionCache). With Ninject you can do something like:
.WithConstructorArgument("session",ninjectContext=>HttpContext.Session);
And after that you can finally make your controllers dependent on ICache.
In your unit tests project you can create another ICache concrete class, something like DummyCache with in-memory cache. So you can test your controllers without sticking to Session object.

How MeController constractor calls?

When I create default SPA template progect VS2013 creates MeController. Calling Get I have a user information. But when I create almost the same Controller, for example UserController, and copy-paste all from Me to User I do not have necessary info about user on breakpoint in the method:
// GET api/Me
public GetViewModel Get()
{
var user = UserManager.FindById(User.Identity.GetUserId());
return new GetViewModel() { Hometown = user.Hometown };
}
I don't uderstand this magic! I also do not see a caller of constractor and sender of userManager. Where is it?
public MeController(ApplicationUserManager userManager)
{
UserManager = userManager;
}
There is a default constructor in the MeController which gets called by default. In this case the UserManager, is got from the Owin contect as below
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
Even if you copy this over to a new class like UserController, this should happen. Are you using any DI library like StrucuteMap/Unity etc? Certain DI controllers choose the 'greediest' constructor(the one with the maximum arguments). You could override that by using appropriate methods for that DI library(like this if you are using StructureMap)
In case you would want to use your own UserManager you could use your own implementation of UserManager and have it used. But if you are planning to stick with the default, this is already added in Startup.Auth.cs into the Owin pipeline.

Session variables in ASP.NET MVC

I am writing a web application that will allow a user to browse to multiple web pages within the website making certain requests. All information that the user inputs will be stored in an object that I created. The problem is that I need this object to be accessed from any part of the website and I don't really know the best way to accomplish this. I know that one solution is to use session variables but I don't know how to use them in asp .net MVC. And where would I declare a session variable? Is there any other way?
I would think you'll want to think about if things really belong in a session state. This is something I find myself doing every now and then and it's a nice strongly typed approach to the whole thing but you should be careful when putting things in the session context. Not everything should be there just because it belongs to some user.
in global.asax hook the OnSessionStart event
void OnSessionStart(...)
{
HttpContext.Current.Session.Add("__MySessionObject", new MySessionObject());
}
From anywhere in code where the HttpContext.Current property != null you can retrive that object. I do this with an extension method.
public static MySessionObject GetMySessionObject(this HttpContext current)
{
return current != null ? (MySessionObject)current.Session["__MySessionObject"] : null;
}
This way you can in code
void OnLoad(...)
{
var sessionObj = HttpContext.Current.GetMySessionObject();
// do something with 'sessionObj'
}
The answer here is correct, I however struggled to implement it in an ASP.NET MVC 3 app. I wanted to access a Session object in a controller and couldn't figure out why I kept on getting a "Instance not set to an instance of an Object error". What I noticed is that in a controller when I tried to access the session by doing the following, I kept on getting that error. This is due to the fact that this.HttpContext is part of the Controller object.
this.Session["blah"]
// or
this.HttpContext.Session["blah"]
However, what I wanted was the HttpContext that's part of the System.Web namespace because this is the one the Answer above suggests to use in Global.asax.cs. So I had to explicitly do the following:
System.Web.HttpContext.Current.Session["blah"]
this helped me, not sure if I did anything that isn't M.O. around here, but I hope it helps someone!
Because I dislike seeing "HTTPContext.Current.Session" about the place, I use a singleton pattern to access session variables, it gives you an easy to access strongly typed bag of data.
[Serializable]
public sealed class SessionSingleton
{
#region Singleton
private const string SESSION_SINGLETON_NAME = "Singleton_502E69E5-668B-E011-951F-00155DF26207";
private SessionSingleton()
{
}
public static SessionSingleton Current
{
get
{
if ( HttpContext.Current.Session[SESSION_SINGLETON_NAME] == null )
{
HttpContext.Current.Session[SESSION_SINGLETON_NAME] = new SessionSingleton();
}
return HttpContext.Current.Session[SESSION_SINGLETON_NAME] as SessionSingleton;
}
}
#endregion
public string SessionVariable { get; set; }
public string SessionVariable2 { get; set; }
// ...
then you can access your data from anywhere:
SessionSingleton.Current.SessionVariable = "Hello, World!";
Well, IMHO..
never reference a Session inside your view/master page
minimize your useage of Session. MVC provides TempData obj for this, which is basically a Session that lives for a single trip to the server.
With regards to #1, I have a strongly typed Master View which has a property to access whatever the Session object represents....in my instance the stongly typed Master View is generic which gives me some flexibility with regards to strongly typed View Pages
ViewMasterPage<AdminViewModel>
AdminViewModel
{
SomeImportantObjectThatWasInSession ImportantObject
}
AdminViewModel<TModel> : AdminViewModel where TModel : class
{
TModel Content
}
and then...
ViewPage<AdminViewModel<U>>
If you are using asp.net mvc, here is a simple way to access the session.
From a Controller:
{Controller}.ControllerContext.HttpContext.Session["{name}"]
From a View:
<%=Session["{name}"] %>
This is definitely not the best way to access your session variables, but it is a direct route. So use it with caution (preferably during rapid prototyping), and use a Wrapper/Container and OnSessionStart when it becomes appropriate.
HTH
Although I don't know about asp.net mvc, but this is what we should do in a normal .net website. It should work for asp.net mvc also.
YourSessionClass obj=Session["key"] as YourSessionClass;
if(obj==null){
obj=new YourSessionClass();
Session["key"]=obj;
}
You would put this inside a method for easy access.
HTH
There are 3 ways to do it.
You can directly access HttpContext.Current.Session
You can Mock HttpContextBase
Create a extension method for HttpContextBase
I prefer 3rd way.This link is good reference.
Get/Set HttpContext Session Methods in BaseController vs Mocking HttpContextBase to create Get/Set methods
My way of accessing sessions is to write a helper class which encapsulates the various field names and their types. I hope this example helps:
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.SessionState;
namespace dmkp
{
/// <summary>
/// Encapsulates the session state
/// </summary>
public sealed class LoginInfo
{
private HttpSessionState _session;
public LoginInfo(HttpSessionState session)
{
this._session = session;
}
public string Username
{
get { return (this._session["Username"] ?? string.Empty).ToString(); }
set { this._session["Username"] = value; }
}
public string FullName
{
get { return (this._session["FullName"] ?? string.Empty).ToString(); }
set { this._session["FullName"] = value; }
}
public int ID
{
get { return Convert.ToInt32((this._session["UID"] ?? -1)); }
set { this._session["UID"] = value; }
}
public UserAccess AccessLevel
{
get { return (UserAccess)(this._session["AccessLevel"]); }
set { this._session["AccessLevel"] = value; }
}
}
}
Great answers from the guys but I would caution you against always relying on the Session. It is quick and easy to do so, and of course would work but would not be great in all cicrumstances.
For example if you run into a scenario where your hosting doesn't allow session use, or if you are on a web farm, or in the example of a shared SharePoint application.
If you wanted a different solution you could look at using an IOC Container such as Castle Windsor, creating a provider class as a wrapper and then keeping one instance of your class using the per request or session lifestyle depending on your requirements.
The IOC would ensure that the same instance is returned each time.
More complicated yes, if you need a simple solution just use the session.
Here are some implementation examples below out of interest.
Using this method you could create a provider class along the lines of:
public class CustomClassProvider : ICustomClassProvider
{
public CustomClassProvider(CustomClass customClass)
{
CustomClass = customClass;
}
public string CustomClass { get; private set; }
}
And register it something like:
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<ICustomClassProvider>().UsingFactoryMethod(
() => new CustomClassProvider(new CustomClass())).LifestylePerWebRequest());
}
You can use ViewModelBase as base class for all models , this class will take care of pulling data from session
class ViewModelBase
{
public User CurrentUser
{
get { return System.Web.HttpContext.Current.Session["user"] as User };
set
{
System.Web.HttpContext.Current.Session["user"]=value;
}
}
}
You can write a extention method on HttpContextBase to deal with session data
T FromSession<T>(this HttpContextBase context ,string key,Action<T> getFromSource=null)
{
if(context.Session[key]!=null)
{
return (T) context.Session[key];
}
else if(getFromSource!=null)
{
var value = getFromSource();
context.Session[key]=value;
return value;
}
else
return null;
}
Use this like below in controller
User userData = HttpContext.FromSession<User>("userdata",()=> { return user object from service/db });
The second argument is optional it will be used fill session data for that key when value is not present in session.

Resources