Identity User value is null in controller constructor - dependency-injection

I'm using TrackerEnabledDbContext as a library for audit trail and also Autofac library for dependency injection.
I registered my DbContext in Global.asax file as
builder.RegisterType<MyDbContext>().AsSelf().InstancePerRequest();
Then in my controller I have this code on controller constructors
public class MyController : Controller
{
private readonly MyDbContext db;
public MyController(){}
public MyController(MyDbContext db)
{
this.db = db;
if (db != null)
{
db.ConfigureUsername(() => User.Identity.Name);
}
}
The problem I'm facing is that whenever constructor method with db context parameter is initialized, User value is null.
How to modify this codes so that whenever this controller is initialized User value could populate with user values.
Thanks in advance

Related

How to pass a unit of work / entity context across Action filters and Controllers

I am trying to make sure that my MVC application only uses one DbContext per Request in order to reduce number of times a Db connection is open and so there are no concurrency issues.
This means i will need to use the same context in my Global Action Filters as well as my Controllers.
I have tried something like this
public class LayoutFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
MembershipUser loggedInUser = Membership.GetUser();
MyUnitOfWork uow = new MyUnitOfWork();
ViewBag.FullName = uow.UserService.GetUser().FullName
filterContext.ActionParameters["unitOfWork"] = uow;
}
}
However the context is disposed when i try to read it from the controller as shown below
public ActionResult Logout(MyUnitOfWork uow)
{
ViewBag.Something = uow.ExampleService.GetMyObject();
return RedirectToAction("LogIn");
}
I get the same issue with the context being disposed when i try to share the same unitOfWork object by casting a property of a base controller class
public class BaseController : Controller
{
public RequestboxUnitOfWork unitOfWork;
}
public class LayoutFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
MembershipUser loggedInUser = Membership.GetUser();
BaseController baseController = (BaseController)filterContext.Controller;
ViewBag.FullName = baseController.unitOfWork.UserService.GetUser().FullName
filterContext.ActionParameters["unitOfWork"] = uow;
}
}
The context is disposed when i try to access it in the controller and i have read in a few places that you should not use base controller class so i am unsure of what i can do.
What are the recommended ways to share a entity context between ActionFilters and Controllers
Create the DBContext as part of the Controller setup, and have it available via an internal property on the controller.
public class MyController : Controller
{
private MyUnitOfWork unitOfWork;
internal MyUnitOfWork UnitOfWork
{
get { return unitOfWork; }
}
}
You will then be able to access the context in the filter attribute like this:
MyController controller = (MyController)filterContext.Controller
MyUnitOfWork uow = controller.UnitOfWork;
There's no need to pass the unit of work back to the action method in the controller, because the controller already has the object, and it can be accessed via the same internal property.

ModelBindingContext.ValueProvider.GetValue(bindingContext.ModelName) returns null

I have bindingContext.ValueProvider.GetValue(bindingContext.ModelName) for ModelBinding and it returns null, but if I use bindingContext.ValueProvider.GetValue("id") is returns the correct record. Any Idea what's missing? Am I supposed to register the model class somehow?
public class EntityModelBinder<TEntity>: IModelBinder where TEntity : Entity
{
private readonly IUnitOfWork unitOfWork;
public EntityModelBinder(IUnitOfWork unitOfWork)
{
this.unitOfWork = unitOfWork;
}
public object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
ValueProviderResult value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
var id = Guid.Parse(value.AttemptedValue);
var entity = ((IGenericRepository<TEntity>)unitOfWork.GetRepository(typeof(TEntity))).GetByID(id);
return entity;
}
}
And Controller Call is "Bill" is one of my Entity Classes, and it's part of the UnitOfWork:
public ActionResult Edit(Bill bill)
{
var model = Mapper.Map<Bill, BillEditModel>(bill);
return View("Edit",model);
}
I am not an expert on mvc, but I have an idea about your issue. I am assuming that you are trying to get a Bill entity from your unit of work. Your action method defines the parameter Bill bill. This means that MVC will set bindingContext.ModelName to "bill", not "id".
Instead of trying to get Bill entity through model binding, I suggest using your unit of work within the controller. So the Edit action could be like
public ActionResult Edit(Guid id)
{
Bill bill = _unitOfWork.GetByID(id);
}
and your Controller constructor might be like:
public MyController(IUnitOfWork uow) {
_unitOfWork = uow;
}
This is assuming that you are using DI.
I think, using the model binder for getting entities from repository could be dangerous. Unless your GetByID method throws an exception, MVC will continue searching for Bill entity in request data. Imagine a scenario, where user posts a new entity that does not exist in your repository. Your controller will have to do some extra work to check whether this entity really exists in your repository.
You are better off using your unit of work within the controller.

I want to use session in the asp.net mvc controller constructor

I'm new to Mvc.
Sorry to my english. ^^
I have some question about asp.net MVC session in the controller.
The Scenario things that I want to do is like follows..
First of all, My development circumstance is entityframework and mvc3.
When Someone logged in each one has different database. So, Each has connect different database.
So, Each person has his own session value which is database connection string. So far so good.
I have simple database Repository and at the each repository's constructor can change database connection.
At controller which calls Repository class, I need session value. But As I know Controller's construction can't keep session value. right?
I want your good advice. Thanks in advance.
Code samples are below:
public class MasterRepository
{
DBEntities _db;
public MasterRepository(string con)
{
_db = new DBEntities(con);
}
}
public class TestController : Controller
{
private string con;
MasterRepository _db;
public TestController()
{
_db = new MasterRepository(Session["conn"].ToString()); // Session is null I want to solve this Part...
}
public ActionResult Index()
{
string con = Session["conn"].ToString(); // Session is assigned.
return View();
}
}
These should explain what's happening to cause Session to be null, and give you a few possible solution options:
Is ASP.NET MVC Session available at any point durign controller construction
Why my session variables are not available at construction of a Controller?
Session null in ASP.Net MVC Controller Constructors
I think you have missed out the "service" part of the controller - service - repository pattern:
http://weblogs.asp.net/fredriknormen/archive/2008/04/24/what-purpose-does-the-repository-pattern-have.aspx
But when you go down this path you will probably also need to learn IoC as well.
Then your code would look more like:
public class MasterRepository
{
public Foo GetAllFoo()
{
return ObjectContextManager.GetObjectContext().AsQueryable().ToList();
}
}
public class MasterService
{
MasterRepository _repository;
public MasterService(MasterRepository repository) // use IoC
{
_repository = repository;
}
public Foo GetAllFoo()
{
return _repository.GetAllFoo();
}
}
public class TestController : Controller
{
MasterService _service;
public TestController(MasterService service) // use IoC
{
_service = service;
}
public ActionResult Index()
{
var model _service.GetAllFoo();
return View(model);
}
}

Injecting a specific instance of an interface using Autofac

I am using ASP.NET MVC 3 and Autofac for my dependency injection. I am using AutoMapper for my mapping.
I have an IMapper class that I use for all my model view mappings. So any any of my mapping classes can implement this interface. In the controller below the constructor receives an IMapper instance, and in my User controller it might receive a different instance, maybe userMapper. Getting back to the code below, I have a class called NewsMapper and it implements IMapper. How do I setup dependency injection so that this controller must receive an instance of NewsMapper? Please bear in mind that I might have another mapper called UserMapper.
I have the following controller:
public class NewsController
{
private INewsService newsService;
private IMapper newsMapper;
public NewsController(INewsService newsService, IMapper newsMapper)
{
if (newsService == null)
{
throw new ArgumentNullException("newsService");
}
if (newsMapper == null)
{
throw new ArgumentNullException("newsMapper");
}
this.newsService = newsService;
this.newsMapper = newsMapper;
}
}
I have the following configuration in my global.asax.cs:
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<NewsService>().As<INewsService>();
builder.RegisterType<NewsRepository>().As<INewsRepository>();
UPDATED:
My IMapper interface:
public interface IMapper
{
object Map(object source, Type sourceType, Type destinationType);
}
My NewsMapper class:
public class NewsMapper : IMapper
{
static NewsMapper()
{
Mapper.CreateMap<News, NewsViewModel>();
Mapper.CreateMap<NewsViewModel, News>();
}
public object Map(object source, Type sourceType, Type destinationType)
{
return Mapper.Map(source, sourceType, destinationType);
}
}
My controller action method where I do the mappings:
[HttpPost]
public ActionResult Create(NewsViewModel newsViewModel)
{
// Check model state
if (!ModelState.IsValid)
{
return View("Create", newsViewModel);
}
// Do mapping
var news = (News)newsMapper.Map(newsViewModel, typeof(NewsViewModel), typeof(News));
// Add to database via news service
// Redirect to list view
return RedirectToAction("List", "News");
}
The problem here is the broadness of the IMapper contract. It is too general - the NewsController wants to map something like News to NewsViewModel but IMapper just says "maps something to something."
Instead, have a look at creating a generic variant such as IMapper<TFrom,TTo>. Then, you can set up container so that the NewsController receives an IMapper<News,NewsModel> which is unambiguous and should uniquely match the NewsMapper component (however you decide to set that up.)
Edit
For examples/variants on the generic mapper theme see:
http://consultingblogs.emc.com/owainwragg/archive/2010/12/15/automapper-profiles.aspx
http://lucisferre.net/2009/12/31/graphite-update-the-automapfilter-for-model-e280933e-viewmodel-mapping/
Specifying a default Unity type mapping for a generic interface and class pair

ASP.NET MVC application controller constructor problem

I've created an application controller abstract class that my controllers derive from (As described in the following article)
The following is an example of what my code looks like
public abstract class ApplicationController : Controller
{
private ProjectDataContext datacontext = new ProjectDataContext();
protected ProjectDataContext DataContext
{
get { return datacontext; }
}
public ApplicationController()
{
ViewData["OpenTasks"] = DataContext.Tasks.Where(t => t.UserId == this.UserId).Count();
}
}
This produces the following error which i have determined is due to the "Where" lamda expression:
If the controller doesn't have a controller factory, ensure that it has a parameterless public constructor.
this error is produced whichever way i write the LINQ query and the only way to compile the application is by removing the "Where" clause as follows.
ViewData["OpenTasks"] = DataContext.Tasks.Count();
any ideas what the problem is or how to resolve this as i need to execute the query against the user and not return all entries.
thanks in advance
Try this instead of using the constructor:-
public abstract class ApplicationController : Controller
{
private ProjectDataContext datacontext = new ProjectDataContext();
protected ProjectDataContext DataContext
{
get { return datacontext; }
}
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
base.Initialize(RequestContext);
ViewData["OpenTasks"] = DataContext.Tasks.Where(t => t.UserId == this.UserId).Count();
}
}
Its quite likely that the current user ID is dependand on the RequestContext
It could be that the call is crashing in the constructor because the UserId (this.UserId) hasn't been initialised yet.

Resources