From 67f8b8f88ba9ffd8d0af6484e7fe14dcd0ac3cf4 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 13 Mar 2014 18:24:37 +1100 Subject: [PATCH] Fixes: U4-3606 Handle caching issues from server requests correctly --- .../Repositories/StylesheetRepository.cs | 21 ++++++++ .../common/resources/stylesheet.resource.js | 4 +- .../Editors/StylesheetController.cs | 16 ++++-- src/Umbraco.Web/Umbraco.Web.csproj | 1 + .../Filters/DisableBrowserCacheAttribute.cs | 54 +++++++++++++++++++ 5 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 src/Umbraco.Web/WebApi/Filters/DisableBrowserCacheAttribute.cs diff --git a/src/Umbraco.Core/Persistence/Repositories/StylesheetRepository.cs b/src/Umbraco.Core/Persistence/Repositories/StylesheetRepository.cs index 893fce373c..b4a62abe5f 100644 --- a/src/Umbraco.Core/Persistence/Repositories/StylesheetRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/StylesheetRepository.cs @@ -83,6 +83,27 @@ namespace Umbraco.Core.Persistence.Repositories return nodeDto == null ? 0 : nodeDto.NodeId; } + //This should be used later to do GetAll properly without individual selections + private IEnumerable> GetStylesheetIds(string[] paths) + { + var sql = new Sql() + .Select("*") + .From() + .Where("nodeObjectType = @NodeObjectType AND umbracoNode.text in (@aliases)", + new + { + NodeObjectType = UmbracoObjectTypes.Stylesheet.GetGuid(), + aliases = paths.Select(x => x.TrimEnd(".css").Replace("\\", "/")).ToArray() + }); + var dtos = _dbwork.Database.Fetch(sql); + + return dtos.Select(x => new Tuple( + //the id + x.NodeId, + //the original path requested for the id + paths.First(p => p.TrimEnd(".css").Replace("\\", "/") == x.Text))); + } + public override IEnumerable GetAll(params string[] ids) { if (ids.Any()) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/stylesheet.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/stylesheet.resource.js index a68798f38b..f407d8622e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/stylesheet.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/stylesheet.resource.js @@ -63,7 +63,7 @@ function stylesheetResource($q, $http, umbRequestHelper) { umbRequestHelper.getApiUrl( "stylesheetApiBaseUrl", "GetRules", - [{ id: id }]) +"&rnd=" + Math.floor(Math.random()*1001), {cache: false}), + [{ id: id }])), 'Failed to retreive stylesheets '); }, @@ -92,7 +92,7 @@ function stylesheetResource($q, $http, umbRequestHelper) { umbRequestHelper.getApiUrl( "stylesheetApiBaseUrl", "GetRulesByName", - [{ name: name }]) +"&rnd=" + Math.floor(Math.random()*1001), {cache: false}), + [{ name: name }])), 'Failed to retreive stylesheets '); } }; diff --git a/src/Umbraco.Web/Editors/StylesheetController.cs b/src/Umbraco.Web/Editors/StylesheetController.cs index dd44d0a5c2..85dd63c022 100644 --- a/src/Umbraco.Web/Editors/StylesheetController.cs +++ b/src/Umbraco.Web/Editors/StylesheetController.cs @@ -1,13 +1,20 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; +using System.Web; using System.Web.Http; +using System.Web.Services.Description; +using Newtonsoft.Json.Linq; using umbraco.cms.businesslogic.web; using Umbraco.Core.IO; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; +using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.Editors { @@ -15,6 +22,7 @@ namespace Umbraco.Web.Editors /// The API controller used for retrieving available stylesheets /// [PluginController("UmbracoApi")] + [DisableBrowserCache] public class StylesheetController : UmbracoAuthorizedJsonController { public IEnumerable GetAll() @@ -30,19 +38,19 @@ namespace Umbraco.Web.Editors public IEnumerable GetRules(int id) { - var css = new StyleSheet(id); + var css = StyleSheet.GetStyleSheet(id, true, true); if (css == null) - throw new HttpResponseException(System.Net.HttpStatusCode.NotFound); + return Enumerable.Empty(); return css.Properties.Select(x => new StylesheetRule() { Id = x.Id, Name = x.Text, Selector = x.Alias }); } - + public IEnumerable GetRulesByName(string name) { var css = StyleSheet.GetByName(name); if (css == null) - throw new HttpResponseException(System.Net.HttpStatusCode.NotFound); + return Enumerable.Empty(); return css.Properties.Select(x => new StylesheetRule() { Id = x.Id, Name = x.Text, Selector = x.Alias }); } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 333dc6f598..c69ff24b29 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -496,6 +496,7 @@ + diff --git a/src/Umbraco.Web/WebApi/Filters/DisableBrowserCacheAttribute.cs b/src/Umbraco.Web/WebApi/Filters/DisableBrowserCacheAttribute.cs new file mode 100644 index 0000000000..c526317d95 --- /dev/null +++ b/src/Umbraco.Web/WebApi/Filters/DisableBrowserCacheAttribute.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Web; +using System.Web.Http.Controllers; +using System.Web.Http.Filters; +using Umbraco.Core; + +namespace Umbraco.Web.WebApi.Filters +{ + public class DisableBrowserCacheAttribute : ActionFilterAttribute + { + public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) + { + //See: http://stackoverflow.com/questions/17755239/how-to-stop-chrome-from-caching-rest-response-from-webapi + + base.OnActionExecuted(actionExecutedContext); + + //TODO: This should all work without issue! BUT it doesn't, i have a feeling this might be fixed + // in the next webapi version. ASP.Net is overwriting the cachecontrol all the time, some docs are here: + // http://stackoverflow.com/questions/11547618/output-caching-for-an-apicontroller-mvc4-web-api + // and I've checked the source code so doing this should cause it to write the headers we want but it doesnt. + //So I've reverted to brute force on the HttpContext. + //actionExecutedContext.Response.Headers.CacheControl = new CacheControlHeaderValue() + //{ + // NoCache = true, + // NoStore = true, + // MaxAge = new TimeSpan(0), + // MustRevalidate = true + //}; + + HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache); + HttpContext.Current.Response.Cache.SetMaxAge(TimeSpan.Zero); + HttpContext.Current.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches); + HttpContext.Current.Response.Cache.SetNoStore(); + + actionExecutedContext.Response.Headers.Pragma.Add(new NameValueHeaderValue("no-cache")); + if (actionExecutedContext.Response.Content != null) + { + actionExecutedContext.Response.Content.Headers.Expires = + //Mon, 01 Jan 1990 00:00:00 GMT + new DateTimeOffset(1990, 1, 1, 0, 0, 0, TimeSpan.Zero); + } + + + + } + } +}