ASP.NET Cache + Singleton Template

I have a huge XML document that I have to parse to create domain objects.

Since the document is huge, I do not want to analyze it every time the user requests it, but only for the first time, and then saves all objects to the cache.

public List<Product> GetXMLProducts() { if (HttpRuntime.Cache.Get("ProductsXML") != null) { return (List<Product>)(HttpRuntime.Cache.Get("ProductsXML")); } string xmlPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Content\\Products.xml"); XmlReader reader = XmlReader.Create(xmlPath); XDocument doc = XDocument.Load(reader); List<Product> productsList = new List<Product>(); // Parsing the products element HttpRuntime.Cache.Insert("ProductsXML", productsList); return productsList; } 

What is the best way I can get this function to work in singleton and be thread safe?

Fixed saving the object to the cache method (there was a copy-paste error)

+4
source share
2 answers

Create Lazy static and save memory for the entire life of the application. And do not forget about the "true" part, which makes it thread safe.

 public static readonly Lazy<List<Product>> _product = new Lazy<List<Products>>(() => GetProducts(), true); 

To add this to your model, just make it private and return _product.Value;

 public MyModel { ... bunch of methods/properties private static readonly Lazy<List<Product>> _products = new Lazy<List<Products>>(() => GetProducts(), true); private static List<Product> GetProducts() { return DsLayer.GetProducts(); } public List<Product> Products { get { return _products.Value; } } } 

To create a singleton using Lazy <>, use this template.

 public MyClass { private static readonly Lazy<MyClass> _myClass = new Lazy<MyClass>(() => new MyClass(), true); private MyClass(){} public static MyClass Instance { get { return _myClass.Value; } } } 

Update / Edit:

Another lazy pattern to use in context (i.e. session)

Some model that is saved in the session:

 public MyModel { private List<Product> _currentProducts = null; public List<Product> CurrentProducts { get { return this._currentProducts ?? (_currentProducts = ProductDataLayer.GetProducts(this.CurrentCustomer)); } } } 
+9
source

For the record - lazy static (the answer of Chris Gessler who gets +1 from me) is a good solution; in this case, because you always want data in memory. This answer definitely considers using Cache (accessing your somewhat confusing code) and creating another way to initialize the website.

The traditional way to do this is in the Application_Start handler in Global.asax (.cs). However, I am going to show another good way:

Add the WebActivator package to your site using Nuget.

Then add the following code to the new .cs file in the new folder created in the project, called App_Start :

 [assembly: WebActivator.PreApplicationStartMethod(typeof(*your_namespace*.MyInit), "Start", Order = 0)] namespace *your_namespace* { public static class MyInit { public static void Start() { string xmlPath = HostingEnvironment.MapPath("~/Content/Products.xml"); using(var reader = XmlReader.Create(xmlPath)) { XDocument doc = XDocument.Load(reader); List<Product> productsList = new List<Product>(); // Parsing the products element HttpRuntime.Cache.Insert("ProductsXML", productsList); } } } } 

Note. Proper use of Cache.Insert and using for thread reader. There is another strange logical and semantic error in your source code - such an attempt to assign the result of a function and return a value from the cache if it is equal to zero.

Note that you also need to enter some namespaces in the code above - and pay attention to *your_namespace* .

+2
source

All Articles