1

Explanation

The navigation tree (NT) is loaded from an API (that's not in my control) and it shows nodes that are one of a couple of types each (categories, processes, etc), and the loading process is done every time someone goes to my search page (Search.cshtml). Note that I created NT from scratch. It's not a plugin of any kind.

For optimisation purposes, I need to cache the whole NT (every node). The cached NT would then be quickly loaded and filtered per user's permissions, when that user gets to the search page.

Now, I have the methods to load all nodes and filter them per user, I also have a model called partialNavigationTree (pNT) that has 1 method for erasing empty folders, and 3 lists like this List<NavTreeNode>, where NTN is also a model that stores some info that's needed for rendering the node to search page.

So, the goal is to have a static, thread-safe pNT variable, that is loaded when the web app initializes, that a controller's method could read from. I already have a specific class that would hold this variable called static class TheHelper.


My plan

In class RouteConfig, method RegisterRoutes, I would put the code to load the static variable CachedNavigationTree (CNT) from TheHelper class, and then let the controller that shows search page copy the contents of CNT to his local variables, filter the nodes in each node list, and then pass on to the view that local variable. This way I get CNT when the web app starts, and gain speed when loading the NT for each user.


Concerns and questions

  1. How do I declare the static CNT? Is declearing it like this public static CachedNavigationTree { get; set; } going to cause problems when multiple users are trying to read from it at the same time? Is THIS the thread-safe way to protect 1 class variable?
  2. The RouteConfig.RegisterRoutes is the "deepest" function I found (that is closest to the web app startup point), so I put my "do this when app starts" code in there. Is there a "deeper" / better place to put this kind of code in?
  3. Since lists of nodes in pNT model are List<T>s, how do I go about copying those lists? If we had 2 lists, A and B, and lets say A is full, then type in B = A;, than the B list's items would only refer to those in list A, which means that changing list Bs items would change list As items as well and vice versa. Is this correct? Should I worry about the way I copy the lists, or is what I said above false, and I can comfortably say var localList = TheHelper.CachedNavigationTree; ?
  4. This is the way of caching that I came up with with the knowledge I have. I wouldn't be suprised if there was already a premade way of caching class variables in C#/MVC. If it exists, and you know of it, please elaborate.

EDIT

Question 3 is actualy - how to copy a full list into an empty one, and actualy generate the items from the full list again. Because in C#, when you put List<string> A = new ...; List<string> B = A;, then when you change (lets say) first item in B list, that item will also change in A list. So there are actualy just 2 names for the same list, not 2 lists in RAM. Hope this clearars question 3. Also, answer's here. Im sorry for the bad explanation.

Monset
  • 648
  • 5
  • 25
  • It would be better to use `MemoryCache` for storing the data (and you could provide a wrapper for checking if it exists in the cache, and if not then call the api to load it in case the cache is invalidated). Then each time a user navigates to your `Search` page, you just call a method that gets the data (you could initially populate the data on start-up, or just have it populated by the first user navigating to the method. –  Dec 06 '17 at 07:46
  • Its unclear what you think `RouteConfig` has to do with your question. And without seeing at least the basic structure if your model(s) and existing code, its difficult to understand what you asking in point 3 –  Dec 06 '17 at 07:47

1 Answers1

0

1) I think you'd be wiser to use MemoryCache to hold your variables, this will still be accessible throughout the app but is a specific device to hold the data (and is what its designed for). To use it is pretty simple as well. You can find Cache in System.Web.Caching for older pre 3.5 apps or MemoryCache System.Runtime.Caching for newer apps). This will also give you a few additional controls like expirations, configurable size limits, polling intervals etc etc. The primary difference between Cache and MemoryCache is that the newer MemoryCache is also designed to work under systems that aren't directly ASP.NET

2) You probably want to look into the Application Life-cycle details on MSDN. The are more handlers and hooks specifically designed to be tied into for this type of purpose in your global.asax file - whether it be for when the application first starts (Application_Start) or when a request for a page comes in (Application_BeginRequest). You coudl build your cache in the Application_Start and then have it call a expiration callback in order to recalculate (and replace your variable) when things change over time without having to restart your app every time you make a change.

3) I'm sorry I'm not quite getting what your asking here.

4) Personally Id switch to using MemoryCache for this system and caching your data there. If your just sending out a static API value to users who request your navigation tree then I'd also consider implementing Response Caching using the Varysystem

John Mitchell
  • 9,653
  • 9
  • 57
  • 91
  • I stumbled upon `MemoryCache` yesturday, but your question is correct none the less. And you answered my other questions. Thank you very much! – Monset Dec 10 '17 at 19:53