5

I have an MVC4 project that deals with "Courses". Many pages throughout the app need to deal with a list of Courses - user profiles need to pull up the list, the Index view for /Courses needs to pull the list, etc.

Since this data is pretty much always required, I'd like to load it as part of the initial request, so I only have to query the DB one time.

I imagine a scenario where the data gets placed in Layout.cshtml, and then other views can access the Model data as needed, though I don't see a clear way of achieving this. I think I can break the problem into two pieces:

  1. Get the data loaded into Layout.cshtml
  2. Access this data from other views

I'm a bit stuck on both - how can I make this work?

RobVious
  • 12,685
  • 25
  • 99
  • 181
  • Check this out http://stackoverflow.com/questions/5872998/how-can-i-write-dynamic-data-to-page-layout-in-mvc-3-razor – Alex Art. Sep 18 '13 at 18:36
  • @AlexAr That's not the same thing – RobVious Sep 18 '13 at 18:50
  • "so I only have to query the DB one time" -- Each request operates completely on it's own, so no matter what you do, the query will be run each time. The exception to the rule, of course, is if you implement some form of caching; the point, though, is that simply running the query at a higher level than the individual action does not, in itself, make it available to all other actions, without running the query again. – Chris Pratt Sep 18 '13 at 19:53
  • @Chris - I meant for one time for courses. Subsequent calls would be for other data - courses would only be loaded once per session. Does that make sense? – RobVious Sep 19 '13 at 03:07
  • That's what I was saying. Unless you explicitly cache the results of the query using memcache or something, and load subsequent requests for the query from that cache instead of issuing the query to the database, it *will* query each time, even if it's done all the way up at the global.asax level -- each request is unique and does not share anything with the last. – Chris Pratt Sep 19 '13 at 15:16

3 Answers3

7

You should use Cache or OutputCache, put this list into a Partial View, and then render it everywhere you need:

1) Create an Action to pupulate the Partial View. This view will be cached for max duration time, then any access will not generate any overhead:

[NonAction]
[OutputCache(Duration = int.MaxValue, VaryByParam = "none")]
public ActionResult GetCourses()
{
  List<Course> courses = new List<Course>();

  /*Read DB here and populate the list*/

  return PartialView("_Courses", courses);
}

2) Using Chache populating the Partial View in the same way:

[NonAction]
public ActionResult GetCourses()
{
  List<Course> courses = new List<Course>();

  if (this.HttpContext.Cache["courses"] == null)
  {
    /*Read DB here and populate the list*/

    this.HttpContext.Cache["courses"] = courses;
  }
  else
  {
    courses = (List<Course>)this.HttpContext.Cache["courses"];
  }

  return PartialView("_Courses", courses);
}

3) Render this View by Html.Action or Html.RenderAction:

@Html.Action("GetCourses", "ControllerName")

or

@{ Html.RenderAction("GetCourses", "ControllerName"); }

More information about caching: Improving Performance with Output Caching

Fals
  • 6,813
  • 4
  • 23
  • 43
  • Thanks Fals, I'll give this a shot. Would you mind showing me what the _Courses partial might look like? – RobVious Sep 18 '13 at 19:07
  • Well, if you need only the Course list, use (2), and render It in the View as you like for! You can access this.HttpContext.Cache["courses"] or you can reference it in ViewBag or ViewData and then iterate to generate any HTML that you need, every where you need! I just gave an idea for caching this! – Fals Sep 18 '13 at 19:13
  • The reason I ask is because I'm trying to access this data from multiple views - not necessarily partial views. Should I put this partial in Layout.cshtml? If so, how can the other views access the data? – RobVious Sep 19 '13 at 22:07
  • 1
    Or are you saying that I should have a different partial per view that needs the data, each loading from the cache? This would make sense to me... thanks again for your patience – RobVious Sep 19 '13 at 22:09
1

I have two answers, because I'm not sure I understand your desire.

1) Create static helper method:

public static class Helper
{
  public static List<Course> GetCourses()
   {
    return db.Courses.ToList();
    }

}

Then you may call it everythere in View or Layout:

@Helper.GetCourses()

2) I prefere not to render business logic in Views or Layout. I would create BaseController. Get List<Course> in this controller. Other controllers should inherit from BaseController. So in any controller's method you may have the same instance of List<Course>.

Andrey Gubal
  • 3,481
  • 2
  • 18
  • 21
0

Store the courses in HttpContext.Current.Items , this cache the items for the one request which is ideal to your case . or use some third party cache components such as memcache

sino
  • 754
  • 1
  • 7
  • 22