diff --git a/src/Umbraco.Core/Sync/DefaultServerMessenger.cs b/src/Umbraco.Core/Sync/DefaultServerMessenger.cs index 67e7dd3802..2bc9e18467 100644 --- a/src/Umbraco.Core/Sync/DefaultServerMessenger.cs +++ b/src/Umbraco.Core/Sync/DefaultServerMessenger.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using System.Net; using System.Threading; +using System.Web.Script.Serialization; using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using umbraco.interfaces; @@ -44,7 +45,12 @@ namespace Umbraco.Core.Sync if (servers == null) throw new ArgumentNullException("servers"); if (refresher == null) throw new ArgumentNullException("refresher"); - instances.ForEach(x => InvokeDispatchMethod(servers, refresher, MessageType.RefreshById, getNumericId(x))); + //copy local + var idGetter = getNumericId; + + MessageSeversForManyObjects(servers, refresher, MessageType.RefreshById, + x => idGetter(x), + instances); } public void PerformRefresh(IEnumerable servers, ICacheRefresher refresher, Func getGuidId, params T[] instances) @@ -52,7 +58,12 @@ namespace Umbraco.Core.Sync if (servers == null) throw new ArgumentNullException("servers"); if (refresher == null) throw new ArgumentNullException("refresher"); - instances.ForEach(x => InvokeDispatchMethod(servers, refresher, MessageType.RefreshById, getGuidId(x))); + //copy local + var idGetter = getGuidId; + + MessageSeversForManyObjects(servers, refresher, MessageType.RefreshById, + x => idGetter(x), + instances); } public void PerformRemove(IEnumerable servers, ICacheRefresher refresher, Func getNumericId, params T[] instances) @@ -60,7 +71,12 @@ namespace Umbraco.Core.Sync if (servers == null) throw new ArgumentNullException("servers"); if (refresher == null) throw new ArgumentNullException("refresher"); - instances.ForEach(x => InvokeDispatchMethod(servers, refresher, MessageType.RemoveById, getNumericId(x))); + //copy local + var idGetter = getNumericId; + + MessageSeversForManyObjects(servers, refresher, MessageType.RemoveById, + x => idGetter(x), + instances); } public void PerformRemove(IEnumerable servers, ICacheRefresher refresher, params int[] numericIds) @@ -68,7 +84,7 @@ namespace Umbraco.Core.Sync if (servers == null) throw new ArgumentNullException("servers"); if (refresher == null) throw new ArgumentNullException("refresher"); - numericIds.ForEach(x => InvokeDispatchMethod(servers, refresher, MessageType.RemoveById, x)); + MessageSeversForManyIds(servers, refresher, MessageType.RemoveById, numericIds.Cast()); } public void PerformRefresh(IEnumerable servers, ICacheRefresher refresher, params int[] numericIds) @@ -76,7 +92,7 @@ namespace Umbraco.Core.Sync if (servers == null) throw new ArgumentNullException("servers"); if (refresher == null) throw new ArgumentNullException("refresher"); - numericIds.ForEach(x => InvokeDispatchMethod(servers, refresher, MessageType.RefreshById, x)); + MessageSeversForManyIds(servers, refresher, MessageType.RefreshById, numericIds.Cast()); } public void PerformRefresh(IEnumerable servers, ICacheRefresher refresher, params Guid[] guidIds) @@ -84,62 +100,155 @@ namespace Umbraco.Core.Sync if (servers == null) throw new ArgumentNullException("servers"); if (refresher == null) throw new ArgumentNullException("refresher"); - guidIds.ForEach(x => InvokeDispatchMethod(servers, refresher, MessageType.RefreshById, x)); - + MessageSeversForManyIds(servers, refresher, MessageType.RefreshById, guidIds.Cast()); } public void PerformRefreshAll(IEnumerable servers, ICacheRefresher refresher) { - InvokeDispatchMethod(servers, refresher, MessageType.RefreshAll, null); + MessageSeversForManyIds(servers, refresher, MessageType.RefreshAll, Enumerable.Empty().ToArray()); } - private void InvokeMethodOnRefresherInstance(ICacheRefresher refresher, MessageType dispatchType, object id) + private void InvokeMethodOnRefresherInstance(ICacheRefresher refresher, MessageType dispatchType, Func getId, IEnumerable instances) { if (refresher == null) throw new ArgumentNullException("refresher"); - //if we are not, then just invoke the call on the cache refresher - switch (dispatchType) + var stronglyTypedRefresher = refresher as ICacheRefresher; + + foreach (var instance in instances) { - case MessageType.RefreshAll: - refresher.RefreshAll(); - break; - case MessageType.RefreshById: - if (id is int) - { - refresher.Refresh((int)id); - } - else if (id is Guid) - { - refresher.Refresh((Guid) id); - } - else - { - throw new InvalidOperationException("The id must be either an int or a Guid"); - } - - break; - case MessageType.RemoveById: - refresher.Remove((int)id); - break; + //if we are not, then just invoke the call on the cache refresher + switch (dispatchType) + { + case MessageType.RefreshAll: + refresher.RefreshAll(); + break; + case MessageType.RefreshById: + if (stronglyTypedRefresher != null) + { + stronglyTypedRefresher.Refresh(instance); + } + else + { + var id = getId(instance); + if (id is int) + { + refresher.Refresh((int)id); + } + else if (id is Guid) + { + refresher.Refresh((Guid)id); + } + else + { + throw new InvalidOperationException("The id must be either an int or a Guid"); + } + } + break; + case MessageType.RemoveById: + if (stronglyTypedRefresher != null) + { + stronglyTypedRefresher.Remove(instance); + } + else + { + var id = getId(instance); + refresher.Refresh((int)id); + } + break; + } } } - private void InvokeDispatchMethod( - IEnumerable servers, - ICacheRefresher refresher, - MessageType dispatchType, - object id) + private void InvokeMethodOnRefresherInstance(ICacheRefresher refresher, MessageType dispatchType, IEnumerable ids) + { + if (refresher == null) throw new ArgumentNullException("refresher"); + + //if it is a refresh all we'll do it here since ids will be null or empty + if (dispatchType == MessageType.RefreshAll) + { + refresher.RefreshAll(); + } + else + { + foreach (var id in ids) + { + //if we are not, then just invoke the call on the cache refresher + switch (dispatchType) + { + case MessageType.RefreshById: + if (id is int) + { + refresher.Refresh((int)id); + } + else if (id is Guid) + { + refresher.Refresh((Guid)id); + } + else + { + throw new InvalidOperationException("The id must be either an int or a Guid"); + } + + break; + case MessageType.RemoveById: + refresher.Remove((int)id); + break; + } + } + } + + + + } + + private void MessageSeversForManyObjects( + IEnumerable servers, + ICacheRefresher refresher, + MessageType dispatchType, + Func getId, + IEnumerable instances) { if (servers == null) throw new ArgumentNullException("servers"); if (refresher == null) throw new ArgumentNullException("refresher"); - if (!(id is int) && (!(id is Guid))) throw new ArgumentException("The id must be either an int or a Guid"); //Now, check if we are using Distrubuted calls. If there are no servers in the list then we // can definitely not distribute. if (!_useDistributedCalls || !servers.Any()) { //if we are not, then just invoke the call on the cache refresher - InvokeMethodOnRefresherInstance(refresher, dispatchType, id); + InvokeMethodOnRefresherInstance(refresher, dispatchType, getId, instances); + return; + } + + //if we are distributing calls then we'll need to do it by id + MessageSeversForManyIds(servers, refresher, dispatchType, instances.Select(getId)); + } + + private void MessageSeversForManyIds( + IEnumerable servers, + ICacheRefresher refresher, + MessageType dispatchType, + IEnumerable ids) + { + if (servers == null) throw new ArgumentNullException("servers"); + if (refresher == null) throw new ArgumentNullException("refresher"); + Type arrayType = null; + foreach (var id in ids) + { + if (!(id is int) && (!(id is Guid))) + throw new ArgumentException("The id must be either an int or a Guid"); + if (arrayType == null) + arrayType = id.GetType(); + if (arrayType != id.GetType()) + throw new ArgumentException("The array must contain the same type of " + arrayType); + } + + //Now, check if we are using Distrubuted calls. If there are no servers in the list then we + // can definitely not distribute. + if (!_useDistributedCalls || !servers.Any()) + { + //if we are not, then just invoke the call on the cache refresher + InvokeMethodOnRefresherInstance(refresher, dispatchType, ids); return; } @@ -152,9 +261,8 @@ namespace Umbraco.Core.Sync LogStartDispatch(); - var nodes = servers; // Go through each configured node submitting a request asynchronously - foreach (var n in nodes) + foreach (var n in servers) { //set the server address cacheRefresher.Url = n.ServerAddress; @@ -168,21 +276,29 @@ namespace Umbraco.Core.Sync refresher.UniqueIdentifier, _login, _password, null, null)); break; case MessageType.RefreshById: - IAsyncResult result; - if (id is int) + if (arrayType == typeof(int)) { - result = cacheRefresher.BeginRefreshById(refresher.UniqueIdentifier, (int) id, _login, _password, null, null); + var serializer = new JavaScriptSerializer(); + var jsonIds = serializer.Serialize(ids.Cast().ToArray()); + //we support bulk loading of Integers + var result = cacheRefresher.BeginRefreshByIds(refresher.UniqueIdentifier, jsonIds, _login, _password, null, null); + asyncResultsList.Add(result); } else { - result = cacheRefresher.BeginRefreshByGuid(refresher.UniqueIdentifier, (Guid)id, _login, _password, null, null); + //we don't currently support bulk loading of GUIDs (not even sure if we have any Guid ICacheRefreshers) + //so we'll just iterate + asyncResultsList.AddRange( + ids.Select(i => cacheRefresher.BeginRefreshByGuid( + refresher.UniqueIdentifier, (Guid) i, _login, _password, null, null))); } - asyncResultsList.Add(result); - break; + + break; case MessageType.RemoveById: - asyncResultsList.Add( - cacheRefresher.BeginRemoveById( - refresher.UniqueIdentifier, (int)id, _login, _password, null, null)); + //we don't currently support bulk removing so we'll iterate + asyncResultsList.AddRange( + ids.Select(i => cacheRefresher.BeginRemoveById( + refresher.UniqueIdentifier, (int)i, _login, _password, null, null))); break; } } @@ -207,7 +323,7 @@ namespace Umbraco.Core.Sync cacheRefresher.EndRefreshAll(t); break; case MessageType.RefreshById: - if (id is int) + if (arrayType == typeof(int)) { cacheRefresher.EndRefreshById(t); } diff --git a/src/Umbraco.Core/Sync/ICacheRefresher.cs b/src/Umbraco.Core/Sync/ICacheRefresher.cs new file mode 100644 index 0000000000..eeb93184f8 --- /dev/null +++ b/src/Umbraco.Core/Sync/ICacheRefresher.cs @@ -0,0 +1,18 @@ +using umbraco.interfaces; + +namespace Umbraco.Core.Sync +{ + /// + /// Strongly type cache refresher that is able to refresh cache of real instances of objects as well as IDs + /// + /// + /// + /// This is much better for performance when we're not running in a load balanced environment so we can refresh the cache + /// against a already resolved object instead of looking the object back up by id. + /// + interface ICacheRefresher : ICacheRefresher + { + void Refresh(T instance); + void Remove(T instance); + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Sync/ServerSyncWebServiceClient.cs b/src/Umbraco.Core/Sync/ServerSyncWebServiceClient.cs index 4df81e8968..ca2add64d4 100644 --- a/src/Umbraco.Core/Sync/ServerSyncWebServiceClient.cs +++ b/src/Umbraco.Core/Sync/ServerSyncWebServiceClient.cs @@ -1,4 +1,5 @@ -using System.Web.Services; +using System.Collections.Generic; +using System.Web.Services; using Umbraco.Core.IO; namespace Umbraco.Core.Sync @@ -73,7 +74,11 @@ namespace Umbraco.Core.Sync } /// - [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://umbraco.org/webservices/RefreshById", RequestNamespace = "http://umbraco.org/webservices/", ResponseNamespace = "http://umbraco.org/webservices/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://umbraco.org/webservices/RefreshById", + RequestNamespace = "http://umbraco.org/webservices/", + ResponseNamespace = "http://umbraco.org/webservices/", + Use = System.Web.Services.Description.SoapBindingUse.Literal, + ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] public void RefreshById(System.Guid uniqueIdentifier, int Id, string Login, string Password) { this.Invoke("RefreshById", new object[] { @@ -99,6 +104,40 @@ namespace Umbraco.Core.Sync this.EndInvoke(asyncResult); } + + /// + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://umbraco.org/webservices/RefreshByIds", + RequestNamespace = "http://umbraco.org/webservices/", + ResponseNamespace = "http://umbraco.org/webservices/", + Use = System.Web.Services.Description.SoapBindingUse.Literal, + ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] + public void RefreshByIds(System.Guid uniqueIdentifier, string jsonIds, string Login, string Password) + { + this.Invoke("RefreshByIds", new object[] { + uniqueIdentifier, + jsonIds, + Login, + Password}); + } + + /// + public System.IAsyncResult BeginRefreshByIds(System.Guid uniqueIdentifier, string jsonIds, string Login, string Password, System.AsyncCallback callback, object asyncState) + { + return this.BeginInvoke("RefreshByIds", new object[] { + uniqueIdentifier, + jsonIds, + Login, + Password}, callback, asyncState); + } + + /// + public void EndRefreshByIds(System.IAsyncResult asyncResult) + { + this.EndInvoke(asyncResult); + } + + + /// [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://umbraco.org/webservices/RemoveById", RequestNamespace = "http://umbraco.org/webservices/", ResponseNamespace = "http://umbraco.org/webservices/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] public void RemoveById(System.Guid uniqueIdentifier, int Id, string Login, string Password) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 7420e3018a..8fca0351d7 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -61,6 +61,7 @@ + True ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.Helpers.dll @@ -669,6 +670,7 @@ + Component diff --git a/src/Umbraco.Tests/Sync/DistributedCacheTests.cs b/src/Umbraco.Tests/Sync/DistributedCacheTests.cs index e8fa316605..847e947599 100644 --- a/src/Umbraco.Tests/Sync/DistributedCacheTests.cs +++ b/src/Umbraco.Tests/Sync/DistributedCacheTests.cs @@ -45,6 +45,19 @@ namespace Umbraco.Tests.Sync Assert.AreEqual(10, ((TestServerMessenger)ServerMessengerResolver.Current.Messenger).IntIdsRefreshed.Count); } + [Test] + public void RefreshIntIdFromObject() + { + for (var i = 0; i < 10; i++) + { + DistributedCache.Instance.Refresh( + Guid.Parse("E0F452CB-DCB2-4E84-B5A5-4F01744C5C73"), + x => x.Id, + new TestObjectWithId{Id = i}); + } + Assert.AreEqual(10, ((TestServerMessenger)ServerMessengerResolver.Current.Messenger).IntIdsRefreshed.Count); + } + [Test] public void RefreshGuidId() { @@ -77,6 +90,11 @@ namespace Umbraco.Tests.Sync #region internal test classes + internal class TestObjectWithId + { + public int Id { get; set; } + } + internal class TestCacheRefresher : ICacheRefresher { public Guid UniqueIdentifier diff --git a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs index 29424ae93b..9dfd262b6e 100644 --- a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs +++ b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs @@ -102,28 +102,22 @@ namespace Umbraco.Web.Cache static void MediaServiceTrashing(IMediaService sender, Core.Events.MoveEventArgs e) { - DistributedCache.Instance.RemoveMediaCache(e.Entity.Id); + DistributedCache.Instance.RemoveMediaCache(e.Entity); } static void MediaServiceMoving(IMediaService sender, Core.Events.MoveEventArgs e) { - DistributedCache.Instance.RefreshMediaCache(e.Entity.Id); + DistributedCache.Instance.RefreshMediaCache(e.Entity); } static void MediaServiceDeleting(IMediaService sender, Core.Events.DeleteEventArgs e) { - foreach (var item in e.DeletedEntities) - { - DistributedCache.Instance.RemoveMediaCache(item.Id); - } + DistributedCache.Instance.RemoveMediaCache(e.DeletedEntities.ToArray()); } static void MediaServiceSaved(IMediaService sender, Core.Events.SaveEventArgs e) { - foreach (var item in e.SavedEntities) - { - DistributedCache.Instance.RefreshMediaCache(item.Id); - } + DistributedCache.Instance.RefreshMediaCache(e.SavedEntities.ToArray()); } static void MemberBeforeDelete(Member sender, DeleteEventArgs e) diff --git a/src/Umbraco.Web/Cache/DistributedCache.cs b/src/Umbraco.Web/Cache/DistributedCache.cs index 8b8582f507..6793454894 100644 --- a/src/Umbraco.Web/Cache/DistributedCache.cs +++ b/src/Umbraco.Web/Cache/DistributedCache.cs @@ -132,6 +132,23 @@ namespace Umbraco.Web.Cache GetRefresherById(factoryGuid), id); } + + /// + /// Sends a request to all registered load-balanced servers to remove the node specified + /// using the specified ICacheRefresher with the guid factoryGuid. + /// + /// + /// + /// + /// + public void Remove(Guid factoryGuid, Func getNumericId, params T[] instances) + { + ServerMessengerResolver.Current.Messenger.PerformRemove( + ServerRegistrarResolver.Current.Registrar.Registrations, + GetRefresherById(factoryGuid), + getNumericId, + instances); + } private static ICacheRefresher GetRefresherById(Guid uniqueIdentifier) { diff --git a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs index 2ce60b42f8..6f9fb9fafd 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs @@ -53,30 +53,40 @@ namespace Umbraco.Web.Cache /// Refreshes the cache amongst servers for a page /// /// - /// - public static void RefreshPageCache(this DistributedCache dc, int pageId) + /// + public static void RefreshPageCache(this DistributedCache dc, int documentId) { - dc.Refresh(new Guid(DistributedCache.PageCacheRefresherId), pageId); - } + dc.Refresh(new Guid(DistributedCache.PageCacheRefresherId), documentId); + } /// /// Refreshes page cache for all instances passed in /// /// /// - public static void RefreshPageCache(this DistributedCache dc, IEnumerable content) + public static void RefreshPageCache(this DistributedCache dc, params IContent[] content) { - dc.Refresh(new Guid(DistributedCache.PageCacheRefresherId), x => x.Id, content.ToArray()); + dc.Refresh(new Guid(DistributedCache.PageCacheRefresherId), x => x.Id, content); } /// /// Removes the cache amongst servers for a page /// /// - /// - public static void RemovePageCache(this DistributedCache dc, int pageId) + /// + public static void RemovePageCache(this DistributedCache dc, params IContent[] content) { - dc.Remove(new Guid(DistributedCache.PageCacheRefresherId), pageId); + dc.Remove(new Guid(DistributedCache.PageCacheRefresherId), x => x.Id, content); + } + + /// + /// Removes the cache amongst servers for a page + /// + /// + /// + public static void RemovePageCache(this DistributedCache dc, int documentId) + { + dc.Remove(new Guid(DistributedCache.PageCacheRefresherId), documentId); } /// @@ -109,6 +119,16 @@ namespace Umbraco.Web.Cache dc.Refresh(new Guid(DistributedCache.MediaCacheRefresherId), mediaId); } + /// + /// Refreshes the cache amongst servers for a media item + /// + /// + /// + public static void RefreshMediaCache(this DistributedCache dc, params IMedia[] media) + { + dc.Refresh(new Guid(DistributedCache.MediaCacheRefresherId), x => x.Id, media); + } + /// /// Removes the cache amongst servers for a media item /// @@ -119,6 +139,16 @@ namespace Umbraco.Web.Cache dc.Remove(new Guid(DistributedCache.MediaCacheRefresherId), mediaId); } + /// + /// Removes the cache amongst servers for media items + /// + /// + /// + public static void RemoveMediaCache(this DistributedCache dc, params IMedia[] media) + { + dc.Remove(new Guid(DistributedCache.MediaCacheRefresherId), x => x.Id, media); + } + /// /// Refreshes the cache amongst servers for a macro item /// diff --git a/src/Umbraco.Web/Cache/PageCacheRefresher.cs b/src/Umbraco.Web/Cache/PageCacheRefresher.cs index f7f6e0703a..4b578a1fe2 100644 --- a/src/Umbraco.Web/Cache/PageCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/PageCacheRefresher.cs @@ -1,5 +1,8 @@ using System; +using Umbraco.Core.Models; +using Umbraco.Core.Sync; using umbraco; +using umbraco.cms.businesslogic.web; using umbraco.interfaces; using umbraco.presentation.cache; @@ -12,7 +15,7 @@ namespace Umbraco.Web.Cache /// If Load balancing is enabled (by default disabled, is set in umbracoSettings.config) PageCacheRefresher will be called /// everytime content is added/updated/removed to ensure that the content cache is identical on all load balanced servers /// - public class PageCacheRefresher : ICacheRefresher + public class PageCacheRefresher : ICacheRefresher { /// /// Gets the unique identifier of the CacheRefresher. @@ -69,5 +72,15 @@ namespace Umbraco.Web.Cache { content.Instance.ClearDocumentCache(id); } + + public void Refresh(IContent instance) + { + content.Instance.UpdateDocumentCache(new Document(instance)); + } + + public void Remove(IContent instance) + { + content.Instance.ClearDocumentCache(new Document(instance)); + } } } diff --git a/src/Umbraco.Web/Strategies/Publishing/UpdateCacheAfterPublish.cs b/src/Umbraco.Web/Strategies/Publishing/UpdateCacheAfterPublish.cs index 99dacfb555..197a88fc56 100644 --- a/src/Umbraco.Web/Strategies/Publishing/UpdateCacheAfterPublish.cs +++ b/src/Umbraco.Web/Strategies/Publishing/UpdateCacheAfterPublish.cs @@ -66,7 +66,7 @@ namespace Umbraco.Web.Strategies.Publishing /// private void UpdateMultipleContentCache(IEnumerable content) { - DistributedCache.Instance.RefreshPageCache(content); + DistributedCache.Instance.RefreshPageCache(content.ToArray()); } /// @@ -74,7 +74,7 @@ namespace Umbraco.Web.Strategies.Publishing /// private void UpdateSingleContentCache(IContent content) { - DistributedCache.Instance.RefreshPageCache(content.Id); + DistributedCache.Instance.RefreshPageCache(content); } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Strategies/Publishing/UpdateCacheAfterUnPublish.cs b/src/Umbraco.Web/Strategies/Publishing/UpdateCacheAfterUnPublish.cs index 942f8d7c34..7af7724c7e 100644 --- a/src/Umbraco.Web/Strategies/Publishing/UpdateCacheAfterUnPublish.cs +++ b/src/Umbraco.Web/Strategies/Publishing/UpdateCacheAfterUnPublish.cs @@ -51,7 +51,7 @@ namespace Umbraco.Web.Strategies.Publishing /// private void UnPublishSingle(IContent content) { - DistributedCache.Instance.RemovePageCache(content.Id); + DistributedCache.Instance.RemovePageCache(content); } } } \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/CacheRefresher.asmx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/CacheRefresher.asmx.cs index d2ecd05a33..23f43d7685 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/CacheRefresher.asmx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/CacheRefresher.asmx.cs @@ -1,9 +1,11 @@ using System; using System.Collections; +using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Web; +using System.Web.Script.Serialization; using System.Web.Services; using System.Xml; using Umbraco.Core; @@ -82,6 +84,29 @@ namespace umbraco.presentation.webservices } } + /// + /// Refreshes objects for all Ids matched in the json string + /// + /// + /// A JSON Serialized string of ids to match + /// + /// + [WebMethod] + public void RefreshByIds(Guid uniqueIdentifier, string jsonIds, string Login, string Password) + { + var serializer = new JavaScriptSerializer(); + var ids = serializer.Deserialize(jsonIds); + + if (BusinessLogic.User.validateCredentials(Login, Password)) + { + var cr = CacheRefreshersResolver.Current.GetById(uniqueIdentifier); + foreach (var i in ids) + { + cr.Refresh(i); + } + } + } + [WebMethod] public void RemoveById(Guid uniqueIdentifier, int Id, string Login, string Password) {