BetterCMS icon indicating copy to clipboard operation
BetterCMS copied to clipboard

CmsController: when storing/retrieving page view model to the HttpRuntimeCacheService, store clone instead of original model

Open Audrunas opened this issue 11 years ago • 0 comments

Reproduce steps:

  1. CMS retrieves page view model from DB with 22 contents
  2. CMS adds it's REFERENCE to the cache
  3. OnPageRendering is fired
  4. Programatically removing 2 contents from model. Because it's runtime cache, these contents are removed from cache also (or updates rendering page model somehow)
  5. 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

Audrunas avatar Nov 17 '14 15:11 Audrunas