Hello Razor MVC Gurus:
Newbie question.
Background. I have a custom IIdentity that is set in an HttpModule before it gets to controller & views. To use it, i have to do
MyIdentity myIdentity = (MyIdentity)((GenericPrincipal)context.User).Identity;
MyComplexUser user = myIdentity.User;
//user.name //user.location //user.username //etc
The problem is, I use the object in different places such as
- master layout
- Some sub level nested layouts
- Some partialviews
- Some views
It really depends on what properties of "MyComplexUser" object the views need.
Currently, in the views, I have to do this really complicated casting to get to a property. For instance, if I want the "Name" of the user, I need to do
@(((MyComplexUser)(((MyIdentity)((GenericPrincipal)context.User).Identity).User)).Name)
I suppose I could put it in the controllers and then populate the ViewBag with a ViewBag.MyUser property, but then
- I don't like to use ViewBag. I prefer strongly typed objects
- If I use a strongly typed object ("MyUser") for views, then I have to popular all those models with a "MyUser" property. Feels a bit dirty? As I like to keep my models clean and be specific to the views they are involved with. Besides, it gets unnecessarily repetitive.
- In places like master_layout.cshtml or partialviews, how do you access "MyUser" if I put them in a controller?
- Use RenderAction and build partialviews for each User property is an overkill?
Thanks. Again, I'm a newbie at MVC 4, any suggestion is greatly appreciate it.
I'll explain a similar solution that works pretty well for me. With small changes, I believe that it will work for you (and others, hopefully) as well.
Basically, we'll be using inheritance.
Controllers
Let's create a custom base controller, such as
public class BaseController : Controller
and let's change our controllers to inherit from it, as
public class HomeController : BaseController
Models (ViewModels, I say)
You probably have lots of classes inside your Models folder, right? They act as DTOs from the controller to the views, right²?
If you answered yes for both, then keep reading.
Let's create a base model class, such as public class BaseVM
, and let's change our models to inherit from it, like public class HomeIndex : BaseVM
Important: your layout file (_Layout
or whatsoever) must be strongly typed to BaseVM
or a child of it.
The hook
Now that everything's beautifuly typed, let's use the request pipeline in our favor.
At BaseController
, you'll add a method that looks like this:
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Result is ViewResultBase)//Gets ViewResult and PartialViewResult
{
object viewModel = ((ViewResultBase)filterContext.Result).Model;
if (viewModel != null && viewModel is BaseVM)
{
BaseVM baseVM = viewModel as BaseVM;
baseVM.MyIdentity = (MyIdentity)((GenericPrincipal)context.User).Identity;
//and so on...
}
}
base.OnActionExecuted(filterContext);//this is important!
}
OnActionExecuted
is called after the execution of the action but before the view rendering. That's exactly what we want.
I hope you got it already. =)