This is the second article in a series about using the .Net 4.0 Caching objects in Asp.Net MVC – catch up first with part 1 of the series, in case you missed it.
In this post I’m going to cover how we can invalidate our repository cache in a more fine-grained, efficient way; instead of simply dropping and re-creating the cache every time something is written to the database, we’re essentially going to replace updated items directly into the cache just after we write them to the database. This will involved hooking into Entity Framework’s change-set and picking out the entities we’re interested in. I’m not going to cover the use of SqlDependancy here and the new wrappers within .Net 4.0.
If you download the sample project now, you can follow along with the article. The sample project (and this article) continue on from where part 1 in this series left off.
Over the course of this article, we’re going to do the following:
- Retrieve the objects which are being inserted, modified or deleted whenever we save changes
- Use the changeset to identify entities which need to be added, updated or removed from the cache
- Create a form to add and edit entities from the UI
So this means we’re basically doing our own invalidation, and the only way the cache will be updated is to update entities through our UI. Any changes made to the data outside of the UI (for example, in Management Studio) will not be picked up unless the cache is explicitly invalidated.
Lets start by making the changes to our IVehicleRepository class.
Here we add support for updating an entity, adding a new entity and persisting the changes to the data store. The new interface looks like this:
public interface IVehicleRepository
{
void ClearCache();
IEnumerable GetVehicles();
void Insert(Vehicle vehicle);
void Update(Vehicle vehicle);
void SaveChanges();
}
We then add the implementation methods. Inserts and updates are fairly standard implementations. For updates, we have to mark the entity as being changed and attach it to the context. For inserts, we simply insert the entity into the Vehicles entity set.
public void Update(Vehicle vehicle)
{
if (vehicle.EntityState == EntityState.Detached)
{
DataContext.AttachTo("Vehicles", vehicle);
}
DataContext.ObjectStateManager.ChangeObjectState(vehicle, EntityState.Modified);
}
public void Insert(Vehicle vehicle)
{
DataContext.AddToVehicles(vehicle);
}
For the implementation of SaveChanges() to work efficiently, we need to make a small change to GetVehicles(). The change is essentially to store a Dictionary of vehicles into the cache instead of a plain list. We can (and should) still return a flat list from the method however to satisfy the interface contract. Here’s the method containing this revision:
public IEnumerable<Vehicle> GetVehicles()
{
// First, check the cache
var vehicleData = Cache.Get("vehicles") as IDictionary<Guid, Vehicle>;
// If it's not in the cache, we need to read it from the repository
if (vehicleData == null)
{
// Get the repository data
vehicleData = DataContext.Vehicles.ToDictionary(v => v.Id);
if (vehicleData.Any())
{
// Put this data into the cache for 30 minutes
Cache.Set("vehicles", vehicleData, 30);
}
}
return vehicleData.Values;
}
Note also that the previous version placed the sorting code here, at the point when the data is read from the database. I’ve simply moved the sorting code outside to the controller, since any entities which are added to the cache could cause it to become unsorted again.
Next, SaveChanges(). Here we simply retrieve the list of changed entities (updated or added), then call SaveChanges() on the underlying data context. Then, we run through the list of changed entities and update the cache directly with the changes. Because the cache now stores a Dictionary, we can simply update or add entities by indexing the dictionary with the ID of the vehicle. The dictionary itself will work out whether or not the entity needs to be added or updated depending on whether it is already in the dictionary or not.
public void SaveChanges()
{
// Update or add new/existing entities from the changeset
var changeset = DataContext.ObjectStateManager
.GetObjectStateEntries(EntityState.Added | EntityState.Modified);
DataContext.SaveChanges();
var cacheData = Cache.Get("vehicles") as Dictionary<Guid, Vehicle>
if (cacheData != null)
{
foreach (var item in changeset)
{
var vehicle = item.Entity as Vehicle;
cacheData[vehicle.Id] = vehicle;
}
}
}
There are a couple of important things to note here:
- By calling SaveChanges() on the data context, we basically wipe out the changed entities. Therefore we need to get the list of changes entities before we actually process them and commit them to the data store.
- We call SaveChanges() before updating the cache because, if the data commit was to fail for whatever reason (validation or some other connection problem) then the cache will still reflect our unchanged data. We didn’t update the cache whenever Update() or Insert() is called for this reason also. We only want the cache to update when the data is actually persisted.
Updating the user interface
All of our code changes regarding data access is now complete. Turning our attention to the UI, we need to create a way to allow the user to insert and update entities via the site. To this end, I am going to create a MVC partial view containing the form, and use it from both the Create and Edit action views.
Firstly, create actions within in the HomeController class called Create and Edit. Note here that we actually create two methods for each action – a GET and a POST action. The actions which have been attributed with [HttpPost] will be called when the form posts back after the submit button has been clicked.
public ActionResult Edit(Guid id)
{
var vehicle = Repository.GetVehicles().Single(v => v.Id == id);
return View(vehicle);
}
[HttpPost]
public ActionResult Edit(Vehicle vehicle)
{
Repository.Update(vehicle);
Repository.SaveChanges();
return RedirectToAction("Index");
}
public ActionResult Create()
{
var newVehicle = new Vehicle() { Id = Guid.NewGuid() };
return View(newVehicle);
}
[HttpPost]
public ActionResult Create(Vehicle vehicle)
{
Repository.Insert(vehicle);
Repository.SaveChanges();
return RedirectToAction("Index");
}
These actions do pretty much as you would expect – when creating, we simply create a new instance of Vehicle and pass it to the view. When editing, we ask the repository to retrieve an instance of Vehicle for us, which in turn uses the cache if available.
Next we need to create the two views; one for creating and one for editing. Create each view by right-clicking on the GET action (the action without the HttpPost attribute) and use the dialogs to create your views. Remember to make them strongly-typed and accept a type of CachingDemo.Web.Models.Vehicle, as we’d like to pass instances of Vehicle to the views and be able to use them in a strongly-typed way from inside the view.
Open the Create view and put in some code to call a partial view named VehicleForm (created next) and pass it the model. If you’ve left the site using the standard template with the master page, the following code should appear within the MainContent placeholder:
<h2>Create</h2>
<% Html.RenderPartial("VehicleForm", Model); %>
<p><%: Html.ActionLink("Back to list", "Index") %></p>
Open the Edit view next copy in exactly the same code as the Create view. The partial view we create next is going to do all the work for us.
Create a partial view inside the /Views/Home folder called “VehicleForm”:
<%@ Control Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<CachingDemo.Web.Models.Data.Vehicle>" %>
<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(true) %>
<%: Html.HiddenFor(m => m.Id) %>
<div>
<%: Html.LabelFor(model => model.Name) %>
</div>
<div>
<%: Html.TextBoxFor(model => model.Name) %>
<%: Html.ValidationMessageFor(model => model.Name) %>
</div>
<div>
<%: Html.LabelFor(model => model.Price) %>
</div>
<div>
<%: Html.TextBoxFor(model => model.Price, String.Format("{0:F}", Model.Price)) %>
<%: Html.ValidationMessageFor(model => model.Price) %>
</div>
<p>
<input type="submit" value="Save" />
</p>
<% } %>
You can also achieve this of course by right-clicking the folder, selecting ‘View’ and then creating a partial view using the dialog. Just remember to make it strongly-typed as we’re going to be passing it an instance of Vehicle as its model from the parent view.
When you’re done, you should now be able to debug the application and watch as single items are retrieved from the cache and replaced in-situ when they are updated. This is more efficient than simply invalidating the whole cache and will scale better when dealing with more users and more data.
Until next time..

Hi Steve,
Nice article(s).
Any idea when part three will be available?
Cheers,
Jules
Hi
Thanks for the comment. Hopefully I’ll have some content for the next in the series soon, although I’m struggling to identify some solid content to follow on from the two articles I’ve done. Is there anything you’d personally like to see addressed/explored in the next article?
Hi
It’s mainly the SqlDependency implementation I’d like to see – the articles I’ve seen on the web over time seem to be sketchy (Sql 2005 implementation, anyway).
Cheers,
Jules
Hi Steve,
It’s a nice article. Can you give some posts in the same methodology with MS-SQL 2000 as a DB(Without using .edmx)? How to cache the data from DB and retrieve it from the cache on the corresponding requests from End-User in ASP.NET MVC2? I’m just looking forward for your posts in MVC.
Thanks,
Thilak R
Hi Thilak,
This is something I’ve had a few emails about, so stay tuned for another part covering this issue shortly!
Hi Steve,
As Jules pointed out, dependencies is a nice article to tackle with, and possible sqldependency under MVC2?
I’ve learned a lot, Thanks!
-imperialx
Pingback: Data Caching with .Net 4.0 and Asp.Net MVC – part 3 « stevescodingblog.co.uk
Hi guys,
Please see part 3 of the series which tackles these issues.
http://stevescodingblog.co.uk/net4-caching-with-mvc-3/
Cheers
Nice articles. Why don’t you try to handle dependency injection by using some IoC framework? It would be really interesting. Thank you anyway
Thanks!
Yep that’s an interesting idea; it’s certainly doable if that’s something you want to see..
Nice series, thanks for sharing these articles!
Anyway, please note that the use of DataContext.AddToVehicles(vehicle); is deprecated. You should use DataContext.Vehicles.AddObject(vehicle); instead.
Hi – thanks for the comment, and thanks for the heads up about AddToVehicles(); I shall modify the article and source code when I get a spare 5 mins!
Hmm, I don’t manage to delete entities (Page objects in my case).
public void Delete(Page page)
{
ClearCache();
_entities.Pages.DeleteObject(page);
}
When calling the above Delete method, an exception is thrown: “The object cannot be deleted because it was not found in the ObjectStateManager.”
How do I successfully delete entities that are being cached your way?
You will have to attach the entity to the context in some way first before deleting. It sounds like the context knows nothing about that entity you’re trying to delete (because it’s previously been detached) hence the exception.
Hmm, this is strange. When I try to attach the entity to the _entities context, an exception is thrown that says that the entity cannot be tracked by two IEntityChangeTrackers.
In other cases when I try to edit an entity, its EntityState property is set to EntityState.Modified but it’s not included in the ObjectStateManager’s change set.
Do you have any idea what the reason for this strange behaviour could be?