I have a pretty common issue: i need to know the name of current user and also name of the current controller so i can highlight/disable some links.
Here's some solutions i found by myself:
1: Get all what's needed inside PartialView.
So i have a PartialView inside my page layout, that takes user name like this:
@{ var userName = Context.ToContext().GetUser<Agent>().Name; }
And here's the way i take controller name:
@{ var controllerName = HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString(); }
I have some problem with this code, for it is suspected to ruin MVC pattern. So i have another solution, which i consider even more stupid.
2: I've created new controller called like "ContextController", here's the code:
public class ContextController : BaseController // BaseController is just a facade
{
public string GetUserName() {
return Context.GetUser<Agent>().Name;
}
}
Here's the problem: i cannot get controller name with this way, cuz it will always be like "Context", which is useless for me. And i also get the name on view like this:
@{ var userName = Html.Action("GetUserName", "Context"); }
3: The last way i figured out is to pass needed strings through ViewData. But i have about 18 controllers and some of 'em have like 3 methods, returning ViewResult. It's not bad design, it's just reality. And i don't actually want to create and pass ViewDataDictionary for every single method, that returns ViewResult. Maybe i could extend my BaseController, so ViewDataDictionary for every page will always have userName and controllerName? But here comes another problem: i have whole lot of AJAX in my project, and it seems to me not legit enough to pass unused data every time controller action is called.
If you know better solution, i'd be happy to hear it. Thanks in advance.
UPD: Well, i've found the solution, that worked for me: I've created an abstract class LayoutViewModel:
public abstract class LayoutViewModel
{
public string UserName { get; set; }
public string UserCode { get; set; }
public ActiveLinkEnum ActiveLink { get; set; }
}
Every ViewModel in my project is now an inherit class for LayoutViewModel. I also extended BaseController class.
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
var viewResult = (ViewResult) filterContext.Result;
var layoutViewModel = (LayoutViewModel) viewResult.Model;
var agent = Context.GetUser<Agent>();
layoutViewModel.UserName = agent.Name;
layoutViewModel.UserCode = agent.Code;
layoutViewModel.ActiveLink = activeLinkResolver.Resolve(filterContext.RouteData.Values["controller"].ToString());
}
So it allowed me: 1. To incapsulate active link determination logic inside builder (IActiveLinkResolver). 2. To easily extend common data on every page. Now my Model doesn't depends on View at all. 3. To evade using of ViewData, which is not an option, due to pt.2.
Thanks to everyone.