1

I'm giving MVC another shot, and I feel like I'm learning freakin' HTML all over again.

So, stupid question: At the top of my master page, I've got a partial view (or similar - I'm using the string template view engine and so far I love it) which either displays a small login form (similar to what NewEgg has), or a message like

You are signed in as (Name). [Profile] | [Sign out]

Unfortunately, I'm having a brain cramp and can't determine the best way to get that data (username, id) into the ViewData collection without explicitly specifying it in every controller method, like

public ActionResult Index()
{
    ViewData["IsAuthenticated"] = Session["IsAuthenticated"];
    ViewData["user.firstname"] = User.FirstName;
    return View("login");
}

That's pretty annoying to have to replicate all over the place. My next option would be to create a method called PopulateCommonViewData() and just call that from every action method, but that also seems lousy.

Am I missing something here?

6 Answers 6

5

Derive your controllers from a base controller. Then move your method creating common view data into the OnActionExecuting/OnActionExecuted override in that base controller.

 public class BaseController : Controller
 {
      public override void OnActionExecuting( ActionExecutingContext filterContext )
      {
           ViewData["IsAuthenticated"] = Request.IsAuthenticated;
           ViewData["user.firstname"] = User.FirstName;
      }
 }

 public class MyController : BaseController // and you're done
 {
    ...
 }
Sign up to request clarification or add additional context in comments.

1 Comment

For the life of me, I can't understand why the project template doesn't ship with a BaseController. EVERYONE I know does it this way except the Microsoft team.
1

I would use ASP.NET membership and just check state and get info from the page context methods in the masterpage. Makes it simple!

2 Comments

And if I need to do this with non-membership data?
Either way, keeping that info in the masterpage is ideal in my opinion. I HATE rewriting even the simplest code, DRY all the way!
1

Couple of options off the top of my head, use a common base controller that all your controllers inherit from which adds the info in the OnActionExecuting method/override or you could possibly use an action filter if it is not required globally...

Comments

1

How about a base ViewModel class which gets injected with the IUserContext & all the other ViewModels in the application derive from this ViewModel?

Somehow, I am not comfortable with the concept of doing: ViewData["magic_string"] = "magic"; pattern recommended here...

Perhaps I am missing a point & would love to know what?

HTH

Comments

0

Do not put these data in ViewData or model at all, and store it in static properties. These static properties could wrap Session or Application state, the ASP.NET cache or the request context bag, whatever is appropriate. So you do not clutter your controller with this kind of global stuff.

4 Comments

Static properties attached to what?
A static class, like e. g. UserContext? You can easily access this from your views. This way you also get rid of the ugly "magic strings" all over the place in your views and your base controller.
Hmm static class - I am not a believer, I would rather have its lifetime managed by a DI container than declaring in the code as static... Please see my comment above & let me know if I am missing something
Interesting idea, however the interface & injection approach appears to be quite complex compared to a simple static class. Especially if you think about all the other kind of context you will face in a web application: current culture/language, user settings, navigation context (which tabs are shown and highlighted in the context of the current request) etc. I don't like the idea to mix all this to together in one big fat base View Model. I try to handle it the same way ASP.NET does it since its beginning with stuff like HttpContext.Current.User etc.
0

Two approaches I could see taking here. One is to use custom action filter attributes to get the data you need into the view model after your controller action executes (the OnResultExecuted method on ActionFilterAttribute would probably do it).

The other is to utilize a base controller class, and override the OnActionExecuted method there.

Since it sounds like you are going to want this on all pages, it seems the latter option would be less maintenance going forward.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.