I've got a simple ASP.NET MVC
controller. Inside a few action methods, I access a resource which I'll say is expensive.
So I thought, why not make it static. So instead of doing double checked locking I thought I can leverage the use of Lazy<T>
in .NET 4.0. Call the expensive service once instead of multiple times.
So, if this is my pseduo code, how can I change it do use Lazy<T>
.
For this contrite example, I'll use the File System
as the expensive resource
So with this example, instead of getting all the files from the destination path, every time a request calls that ActionMethod, I was hoping to use Lazy to hold that list of files .. which of course, makes the call the first time only.
Next assumption: don't worry if the content is changed. That's out of scope, here.
public class FooController : Controller
{
private readonly IFoo _foo;
public FooController(IFoo foo)
{
_foo = foo;
}
public ActionResult PewPew()
{
// Grab all the files in a folder.
// nb. _foo.PathToFiles = "/Content/Images/Harro"
var files = Directory.GetFiles(Server.MapPath(_foo.PathToFiles));
// Note: No, I wouldn't return all the files but a concerete view model
// with only the data from a File object, I require.
return View(files);
}
}
Lazy Loading is a technique that delays the initialization of an object. This is a new feature of C# 4.0. The basic idea of lazy loading is to load objects or data only when they are needed. A lazy loading pattern is also called Object on Demand.
Lazy loading is delaying the loading of related data, until you specifically request for it. It is the opposite of eager loading. For example, the Student entity contains the StudentAddress entity.
Lazy loading is the process whereby an entity or collection of entities is automatically loaded from the database the first time that a property referring to the entity/entities is accessed. Lazy loading means delaying the loading of related data, until you specifically request for it.
In your example, the result of Directory.GetFiles
depends on the value of _foo
, which is not static. Therefore you cannot use a static instance of Lazy<string[]>
as a shared cache between all instances of your controller.
The ConcurrentDictionary<TKey, TValue>
sounds like something that is closer to what you want.
// Code not tested, blah blah blah...
public class FooController : Controller
{
private static readonly ConcurrentDictionary<string, string[]> _cache
= new ConcurrentDictionary<string, string[]>();
private readonly IFoo _foo;
public FooController(IFoo foo)
{
_foo = foo;
}
public ActionResult PewPew()
{
var files = _cache.GetOrAdd(Server.MapPath(_foo.PathToFiles), path => {
return Directory.GetFiles(path);
});
return View(files);
}
}
I agree with Greg that Lazy<> is inappropriate here.
You could try using asp.net caching to cache the contents of a folder, using _foo.PathToFiles as your key. This has an advantage over Lazy<> that you can control the lifetime of the caching so it will refetch the contents say every day or every week without requiring an application restart.
Also caching is friendly to your server in that it will gracefully degrade if there is not enough memory to support it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With