BetterCMS
BetterCMS copied to clipboard
CmsController: when storing/retrieving page view model to the HttpRuntimeCacheService, store clone instead of original model
Reproduce steps:
- CMS retrieves page view model from DB with 22 contents
- CMS adds it's REFERENCE to the cache
- OnPageRendering is fired
- Programatically removing 2 contents from model. Because it's runtime cache, these contents are removed from cache also (or updates rendering page model somehow)
- Next time another user load page, updated model is retrieved (with only 20 contents)
There is a solution, made in one of the projects (overridden cache service + request view model cloning):
using System;
using BetterCms.Core.Services.Caching;
using BetterCms.Module.Root.ViewModels.Cms;
using NHibernate.Linq;
namespace Application.Web.Services.CmsCacheService
{
public class CmsCacheService : ICacheService
{
private readonly HttpRuntimeCacheService _internalCacheService;
public CmsCacheService()
{
_internalCacheService = new HttpRuntimeCacheService();
}
public void Set<T>(string key, T obj, TimeSpan expiration)
{
var requestViewModel = obj as CmsRequestViewModel;
if (requestViewModel != null)
{
var clone = CloneRequest(requestViewModel);
_internalCacheService.Set(key, clone, expiration);
}
else
{
_internalCacheService.Set(key, obj, expiration);
}
}
public T Get<T>(string key)
{
var result = _internalCacheService.Get<T>(key);
var requestViewModel = result as CmsRequestViewModel;
if (requestViewModel != null)
{
var clone = CloneRequest(requestViewModel);
return clone.As<T>();
}
else
{
return result;
}
}
public T Get<T>(string key, TimeSpan expiration, Func<T> getCacheObject)
{
var result = _internalCacheService.Get(key, expiration, getCacheObject);
var requestViewModel = result as CmsRequestViewModel;
if (requestViewModel != null)
{
var clone = CloneRequest(requestViewModel);
return clone.As<T>();
}
else
{
return result;
}
}
public void Remove(string key)
{
_internalCacheService.Remove(key);
}
private CmsRequestViewModel CloneRequest(CmsRequestViewModel request)
{
var clone = new CmsRequestViewModel {Redirect = request.Redirect, RenderPage = request.RenderPage.Clone()};
return clone;
}
}
}
Implement cloning logic in CmsController before storing / after retrieving content in the cache