diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IRepositoryVersionable.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IRepositoryVersionable.cs index c8b6f79f7d..81783ccfbd 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IRepositoryVersionable.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IRepositoryVersionable.cs @@ -12,6 +12,17 @@ namespace Umbraco.Core.Persistence.Repositories public interface IRepositoryVersionable : IRepositoryQueryable where TEntity : IAggregateRoot { + /// + /// Get the total count of entities + /// + /// + /// + int Count(string contentTypeAlias = null); + + int CountChildren(int parentId, string contentTypeAlias = null); + + int CountDescendants(int parentId, string contentTypeAlias = null); + /// /// Gets a list of all versions for an . /// diff --git a/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs index bf68a1a9a2..8729c7d8f2 100644 --- a/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs @@ -96,6 +96,90 @@ namespace Umbraco.Core.Persistence.Repositories #endregion + public int CountDescendants(int parentId, string contentTypeAlias = null) + { + var pathMatch = parentId == -1 + ? "-1," + : "," + parentId + ","; + var sql = new Sql(); + if (contentTypeAlias.IsNullOrWhiteSpace()) + { + sql.Select("COUNT(*)") + .From() + .Where(x => x.NodeObjectType == NodeObjectTypeId) + .Where(x => x.Path.Contains(pathMatch)); + } + else + { + sql.Select("COUNT(*)") + .From() + .InnerJoin() + .On(left => left.NodeId, right => right.NodeId) + .InnerJoin() + .On(left => left.NodeId, right => right.ContentTypeId) + .Where(x => x.NodeObjectType == NodeObjectTypeId) + .Where(x => x.Path.Contains(pathMatch)) + .Where(x => x.Alias == contentTypeAlias); + } + + return Database.ExecuteScalar(sql); + } + + public int CountChildren(int parentId, string contentTypeAlias = null) + { + var sql = new Sql(); + if (contentTypeAlias.IsNullOrWhiteSpace()) + { + sql.Select("COUNT(*)") + .From() + .Where(x => x.NodeObjectType == NodeObjectTypeId) + .Where(x => x.ParentId == parentId); + } + else + { + sql.Select("COUNT(*)") + .From() + .InnerJoin() + .On(left => left.NodeId, right => right.NodeId) + .InnerJoin() + .On(left => left.NodeId, right => right.ContentTypeId) + .Where(x => x.NodeObjectType == NodeObjectTypeId) + .Where(x => x.ParentId == parentId) + .Where(x => x.Alias == contentTypeAlias); + } + + return Database.ExecuteScalar(sql); + } + + /// + /// Get the total count of entities + /// + /// + /// + public int Count(string contentTypeAlias = null) + { + var sql = new Sql(); + if (contentTypeAlias.IsNullOrWhiteSpace()) + { + sql.Select("COUNT(*)") + .From() + .Where(x => x.NodeObjectType == NodeObjectTypeId); + } + else + { + sql.Select("COUNT(*)") + .From() + .InnerJoin() + .On(left => left.NodeId, right => right.NodeId) + .InnerJoin() + .On(left => left.NodeId, right => right.ContentTypeId) + .Where(x => x.NodeObjectType == NodeObjectTypeId) + .Where(x => x.Alias == contentTypeAlias); + } + + return Database.ExecuteScalar(sql); + } + /// /// This removes associated tags from the entity - used generally when an entity is recycled /// diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 6e59526d5f..311e68a482 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -74,6 +74,33 @@ namespace Umbraco.Core.Services _dataTypeService = dataTypeService; } + public int Count(string contentTypeAlias = null) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) + { + return repository.Count(contentTypeAlias); + } + } + + public int CountChildren(int parentId, string contentTypeAlias = null) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) + { + return repository.CountChildren(parentId, contentTypeAlias); + } + } + + public int CountDescendants(int parentId, string contentTypeAlias = null) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) + { + return repository.CountDescendants(parentId, contentTypeAlias); + } + } + /// /// Used to bulk update the permissions set for a content item. This will replace all permissions /// assigned to an entity with a list of user id & permission pairs. diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs index a623b1d8e9..76964e8e9a 100644 --- a/src/Umbraco.Core/Services/IContentService.cs +++ b/src/Umbraco.Core/Services/IContentService.cs @@ -11,6 +11,10 @@ namespace Umbraco.Core.Services /// public interface IContentService : IService { + int Count(string contentTypeAlias = null); + int CountChildren(int parentId, string contentTypeAlias = null); + int CountDescendants(int parentId, string contentTypeAlias = null); + /// /// Used to bulk update the permissions set for a content item. This will replace all permissions /// assigned to an entity with a list of user id & permission pairs. diff --git a/src/Umbraco.Core/Services/IMediaService.cs b/src/Umbraco.Core/Services/IMediaService.cs index 48afe70317..a457f69502 100644 --- a/src/Umbraco.Core/Services/IMediaService.cs +++ b/src/Umbraco.Core/Services/IMediaService.cs @@ -9,6 +9,10 @@ namespace Umbraco.Core.Services /// public interface IMediaService : IService { + int Count(string contentTypeAlias = null); + int CountChildren(int parentId, string contentTypeAlias = null); + int CountDescendants(int parentId, string contentTypeAlias = null); + IEnumerable GetByIds(IEnumerable ids); /// diff --git a/src/Umbraco.Core/Services/IMemberService.cs b/src/Umbraco.Core/Services/IMemberService.cs index f7918b2d8d..5d78f6df86 100644 --- a/src/Umbraco.Core/Services/IMemberService.cs +++ b/src/Umbraco.Core/Services/IMemberService.cs @@ -11,6 +11,8 @@ namespace Umbraco.Core.Services /// public interface IMemberService : IMembershipMemberService { + int Count(string contentTypeAlias = null); + IMember CreateMember(string username, string email, string name, string memberTypeAlias); IMember CreateMember(string username, string email, string name, IMemberType memberType); IMember CreateMemberWithIdentity(string username, string email, string name, string memberTypeAlias); diff --git a/src/Umbraco.Core/Services/MediaService.cs b/src/Umbraco.Core/Services/MediaService.cs index accbba33cb..518be0ef07 100644 --- a/src/Umbraco.Core/Services/MediaService.cs +++ b/src/Umbraco.Core/Services/MediaService.cs @@ -251,6 +251,33 @@ namespace Umbraco.Core.Services } } + public int Count(string contentTypeAlias = null) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaRepository(uow)) + { + return repository.Count(contentTypeAlias); + } + } + + public int CountChildren(int parentId, string contentTypeAlias = null) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaRepository(uow)) + { + return repository.CountChildren(parentId, contentTypeAlias); + } + } + + public int CountDescendants(int parentId, string contentTypeAlias = null) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaRepository(uow)) + { + return repository.CountDescendants(parentId, contentTypeAlias); + } + } + /// /// Gets an object by Id /// diff --git a/src/Umbraco.Core/Services/MemberService.cs b/src/Umbraco.Core/Services/MemberService.cs index 437105c642..ecf2874ea6 100644 --- a/src/Umbraco.Core/Services/MemberService.cs +++ b/src/Umbraco.Core/Services/MemberService.cs @@ -644,6 +644,15 @@ namespace Umbraco.Core.Services } } + public int Count(string contentTypeAlias = null) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMemberRepository(uow)) + { + return repository.Count(contentTypeAlias); + } + } + /// /// Creates a member object /// diff --git a/src/Umbraco.Core/Sync/DefaultServerMessenger.cs b/src/Umbraco.Core/Sync/DefaultServerMessenger.cs index fa9c331b10..f302dbe4d8 100644 --- a/src/Umbraco.Core/Sync/DefaultServerMessenger.cs +++ b/src/Umbraco.Core/Sync/DefaultServerMessenger.cs @@ -20,18 +20,19 @@ namespace Umbraco.Core.Sync { private readonly Func> _getUserNamePasswordDelegate; private volatile bool _hasResolvedDelegate = false; - private readonly object _locker = new object(); - private bool _useDistributedCalls; + private readonly object _locker = new object(); protected string Login { get; private set; } protected string Password{ get; private set; } + protected bool UseDistributedCalls { get; private set; } + /// /// Without a username/password all distribuion will be disabled /// internal DefaultServerMessenger() { - _useDistributedCalls = false; + UseDistributedCalls = false; } /// @@ -55,7 +56,7 @@ namespace Umbraco.Core.Sync if (login == null) throw new ArgumentNullException("login"); if (password == null) throw new ArgumentNullException("password"); - _useDistributedCalls = useDistributedCalls; + UseDistributedCalls = useDistributedCalls; Login = login; Password = password; } @@ -221,13 +222,13 @@ namespace Umbraco.Core.Sync { Login = null; Password = null; - _useDistributedCalls = false; + UseDistributedCalls = false; } else { Login = result.Item1; Password = result.Item2; - _useDistributedCalls = UmbracoConfig.For.UmbracoSettings().DistributedCall.Enabled; + UseDistributedCalls = UmbracoConfig.For.UmbracoSettings().DistributedCall.Enabled; } } catch (Exception ex) @@ -235,7 +236,7 @@ namespace Umbraco.Core.Sync LogHelper.Error("Could not resolve username/password delegate, server distribution will be disabled", ex); Login = null; Password = null; - _useDistributedCalls = false; + UseDistributedCalls = false; } } } @@ -314,7 +315,7 @@ namespace Umbraco.Core.Sync //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 (!UseDistributedCalls || !servers.Any()) { //if we are not, then just invoke the call on the cache refresher InvokeMethodOnRefresherInstance(refresher, dispatchType, getId, instances); @@ -325,7 +326,7 @@ namespace Umbraco.Core.Sync MessageSeversForIdsOrJson(servers, refresher, dispatchType, instances.Select(getId)); } - private void MessageSeversForIdsOrJson( + protected virtual void MessageSeversForIdsOrJson( IEnumerable servers, ICacheRefresher refresher, MessageType dispatchType, @@ -345,7 +346,7 @@ namespace Umbraco.Core.Sync //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 (!UseDistributedCalls || !servers.Any()) { //if we are not, then just invoke the call on the cache refresher InvokeMethodOnRefresherInstance(refresher, dispatchType, ids, jsonPayload); @@ -456,16 +457,16 @@ namespace Umbraco.Core.Sync } } - List waitHandlesList; - var asyncResults = GetAsyncResults(asyncResultsList, out waitHandlesList); - + var waitHandlesList = asyncResultsList.Select(x => x.AsyncWaitHandle).ToArray(); + var errorCount = 0; - // Once for each WaitHandle that we have, wait for a response and log it - // We're previously submitted all these requests effectively in parallel and will now retrieve responses on a FIFO basis - foreach (var t in asyncResults) + //Wait for all requests to complete + WaitHandle.WaitAll(waitHandlesList.ToArray()); + + foreach (var t in asyncResultsList) { - var handleIndex = WaitHandle.WaitAny(waitHandlesList.ToArray(), TimeSpan.FromSeconds(15)); + //var handleIndex = WaitHandle.WaitAny(waitHandlesList.ToArray(), TimeSpan.FromSeconds(15)); try { @@ -520,18 +521,7 @@ namespace Umbraco.Core.Sync LogDispatchBatchError(ee); } } - - internal IEnumerable GetAsyncResults(List asyncResultsList, out List waitHandlesList) - { - var asyncResults = asyncResultsList.ToArray(); - waitHandlesList = new List(); - foreach (var asyncResult in asyncResults) - { - waitHandlesList.Add(asyncResult.AsyncWaitHandle); - } - return asyncResults; - } - + private void LogDispatchBatchError(Exception ee) { LogHelper.Error("Error refreshing distributed list", ee); diff --git a/src/Umbraco.Core/Sync/IServerAddress.cs b/src/Umbraco.Core/Sync/IServerAddress.cs index 78645e0767..0483af1800 100644 --- a/src/Umbraco.Core/Sync/IServerAddress.cs +++ b/src/Umbraco.Core/Sync/IServerAddress.cs @@ -8,5 +8,7 @@ namespace Umbraco.Core.Sync public interface IServerAddress { string ServerAddress { get; } + + //TODO : Should probably add things like port, protocol, server name, app id } } \ No newline at end of file diff --git a/src/Umbraco.Core/Sync/ServerSyncWebServiceClient.cs b/src/Umbraco.Core/Sync/ServerSyncWebServiceClient.cs index 923ed3c670..6a620bc4c3 100644 --- a/src/Umbraco.Core/Sync/ServerSyncWebServiceClient.cs +++ b/src/Umbraco.Core/Sync/ServerSyncWebServiceClient.cs @@ -22,19 +22,21 @@ namespace Umbraco.Core.Sync /// [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://umbraco.org/webservices/BulkRefresh", 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 BulkRefresh(RefreshInstruction[] instructions, string login, string password) + public void BulkRefresh(RefreshInstruction[] instructions, string appId, string login, string password) { this.Invoke("BulkRefresh", new object[] { instructions, + appId, login, password}); } /// - public System.IAsyncResult BeginBulkRefresh(RefreshInstruction[] instructions, string login, string password, System.AsyncCallback callback, object asyncState) + public System.IAsyncResult BeginBulkRefresh(RefreshInstruction[] instructions, string appId, string login, string password, System.AsyncCallback callback, object asyncState) { return this.BeginInvoke("BulkRefresh", new object[] { instructions, + appId, login, password}, callback, asyncState); } diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 75a247f1c8..9e7535b0f3 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -39,6 +39,82 @@ namespace Umbraco.Tests.Services //TODO Add test to verify there is only ONE newest document/content in cmsDocument table after updating. //TODO Add test to delete specific version (with and without deleting prior versions) and versions by date. + [Test] + public void Count_All() + { + // Arrange + var contentService = ServiceContext.ContentService; + + // Act + for (int i = 0; i < 20; i++) + { + contentService.CreateContentWithIdentity("Test", -1, "umbTextpage", 0); + } + + // Assert + Assert.AreEqual(24, contentService.Count()); + } + + [Test] + public void Count_By_Content_Type() + { + // Arrange + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbBlah", "test Doc Type"); + contentTypeService.Save(contentType); + + // Act + for (int i = 0; i < 20; i++) + { + contentService.CreateContentWithIdentity("Test", -1, "umbBlah", 0); + } + + // Assert + Assert.AreEqual(20, contentService.Count(contentTypeAlias: "umbBlah")); + } + + [Test] + public void Count_Children() + { + // Arrange + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbBlah", "test Doc Type"); + contentTypeService.Save(contentType); + var parent = contentService.CreateContentWithIdentity("Test", -1, "umbBlah", 0); + + // Act + for (int i = 0; i < 20; i++) + { + contentService.CreateContentWithIdentity("Test", parent, "umbBlah"); + } + + // Assert + Assert.AreEqual(20, contentService.CountChildren(parent.Id)); + } + + [Test] + public void Count_Descendants() + { + // Arrange + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbBlah", "test Doc Type"); + contentTypeService.Save(contentType); + var parent = contentService.CreateContentWithIdentity("Test", -1, "umbBlah", 0); + + // Act + IContent current = parent; + for (int i = 0; i < 20; i++) + { + current = contentService.CreateContentWithIdentity("Test", current, "umbBlah"); + } + + // Assert + Assert.AreEqual(20, contentService.CountDescendants(parent.Id)); + } + [Test] public void Tags_For_Entity_Are_Not_Exposed_Via_Tag_Api_When_Content_Is_Recycled() { diff --git a/src/Umbraco.Tests/Services/MemberServiceTests.cs b/src/Umbraco.Tests/Services/MemberServiceTests.cs index 9609110308..1ff9947a6f 100644 --- a/src/Umbraco.Tests/Services/MemberServiceTests.cs +++ b/src/Umbraco.Tests/Services/MemberServiceTests.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Models.Membership; @@ -376,6 +377,34 @@ namespace Umbraco.Tests.Services Assert.IsNull(ServiceContext.MemberService.GetByEmail("do@not.find")); } + [Test] + public void Get_Member_Name() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + IMember member = MockedMember.CreateSimpleMember(memberType, "Test Real Name", "test@test.com", "pass", "testUsername"); + ServiceContext.MemberService.Save(member); + + + Assert.AreEqual("Test Real Name", member.Name); + } + + [Test] + public void Get_Member_Name_In_Created_Event() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + + TypedEventHandler> callback = (sender, args) => + { + Assert.AreEqual("Test Real Name", args.Entity.Name); + }; + + MemberService.Created += callback; + var member = ServiceContext.MemberService.CreateMember("testUsername", "test@test.com", "Test Real Name", memberType); + MemberService.Created -= callback; + } + [Test] public void Get_By_Username() { diff --git a/src/Umbraco.Web.UI/umbraco/settings/editTemplate.aspx b/src/Umbraco.Web.UI/umbraco/settings/editTemplate.aspx index babe1c15cb..da36e5ae7d 100644 --- a/src/Umbraco.Web.UI/umbraco/settings/editTemplate.aspx +++ b/src/Umbraco.Web.UI/umbraco/settings/editTemplate.aspx @@ -1,5 +1,8 @@ <%@ Page MasterPageFile="../masterpages/umbracoPage.Master" Language="c#" CodeBehind="EditTemplate.aspx.cs" ValidateRequest="false" AutoEventWireup="True" Inherits="Umbraco.Web.UI.Umbraco.Settings.EditTemplate" %> + +<%@ OutputCache Location="None" %> + <%@ Import Namespace="Umbraco.Core" %> <%@ Import Namespace="Umbraco.Core.Configuration" %> <%@ Import Namespace="Umbraco.Core.IO" %> diff --git a/src/Umbraco.Web.UI/umbraco/settings/views/EditView.aspx b/src/Umbraco.Web.UI/umbraco/settings/views/EditView.aspx index df3d7ead94..2c6fc12f76 100644 --- a/src/Umbraco.Web.UI/umbraco/settings/views/EditView.aspx +++ b/src/Umbraco.Web.UI/umbraco/settings/views/EditView.aspx @@ -2,6 +2,8 @@ CodeBehind="EditView.aspx.cs" Inherits="Umbraco.Web.UI.Umbraco.Settings.Views.EditView" ValidateRequest="False" %> +<%@ OutputCache Location="None" %> + <%@ Import Namespace="Umbraco.Core" %> <%@ Import Namespace="Umbraco.Core.IO" %> <%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %> diff --git a/src/Umbraco.Web/BatchedServerMessenger.cs b/src/Umbraco.Web/BatchedServerMessenger.cs index 669c1de817..9ed2e3fd2c 100644 --- a/src/Umbraco.Web/BatchedServerMessenger.cs +++ b/src/Umbraco.Web/BatchedServerMessenger.cs @@ -67,6 +67,43 @@ namespace Umbraco.Web public string JsonPayload { get; set; } } + /// + /// We need to check if distributed calls are enabled, if they are we also want to make sure + /// that the current server's cache is updated internally in real time instead of at the end of + /// the call. This is because things like the URL cache, etc... might need to be updated during + /// the request that is making these calls. + /// + /// + /// + /// + /// + /// + /// + /// See: http://issues.umbraco.org/issue/U4-2633#comment=67-15604 + /// + protected override void MessageSeversForIdsOrJson(IEnumerable servers, ICacheRefresher refresher, MessageType dispatchType, IEnumerable ids = null, string jsonPayload = null) + { + //do all the normal stuff + base.MessageSeversForIdsOrJson(servers, refresher, dispatchType, ids, jsonPayload); + + //Now, check if we are using Distrubuted calls + if (UseDistributedCalls && servers.Any()) + { + //invoke on the current server - we will basically be double cache refreshing for the calling + // server but that just needs to be done currently, see the link above for details. + InvokeMethodOnRefresherInstance(refresher, dispatchType, ids, jsonPayload); + } + } + + /// + /// This adds the call to batched list + /// + /// + /// + /// + /// + /// + /// protected override void PerformDistributedCall( IEnumerable servers, ICacheRefresher refresher, @@ -75,6 +112,7 @@ namespace Umbraco.Web Type idArrayType = null, string jsonPayload = null) { + //NOTE: we use UmbracoContext instead of HttpContext.Current because when some web methods run async, the // HttpContext.Current is null but the UmbracoContext.Current won't be since we manually assign it. if (UmbracoContext.Current == null || UmbracoContext.Current.HttpContext == null) @@ -205,19 +243,22 @@ namespace Umbraco.Web asyncResultsList.Add( cacheRefresher.BeginBulkRefresh( - instructions, Login, Password, null, null)); + instructions, + HttpRuntime.AppDomainAppId, + Login, Password, null, null)); } - List waitHandlesList; - var asyncResults = GetAsyncResults(asyncResultsList, out waitHandlesList); - + var waitHandlesList = asyncResultsList.Select(x => x.AsyncWaitHandle).ToArray(); + var errorCount = 0; - // Once for each WaitHandle that we have, wait for a response and log it - // We're previously submitted all these requests effectively in parallel and will now retrieve responses on a FIFO basis - foreach (var t in asyncResults) + //Wait for all requests to complete + WaitHandle.WaitAll(waitHandlesList.ToArray()); + + foreach (var t in asyncResultsList) { - var handleIndex = WaitHandle.WaitAny(waitHandlesList.ToArray(), TimeSpan.FromSeconds(15)); + //var handleIndex = WaitHandle.WaitAny(waitHandlesList.ToArray(), TimeSpan.FromSeconds(15)); + try { cacheRefresher.EndBulkRefresh(t); 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 cd992fc71f..3a519dfea1 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/CacheRefresher.asmx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/CacheRefresher.asmx.cs @@ -24,13 +24,26 @@ namespace umbraco.presentation.webservices { [WebMethod] - public void BulkRefresh(RefreshInstruction[] instructions, string login, string password) + public void BulkRefresh(RefreshInstruction[] instructions, string appId, string login, string password) { if (BusinessLogic.User.validateCredentials(login, password) == false) { return; } + //check if this is the same app id as the one passed in, if it is, then we will ignore + // the request - we will have to assume that the cache refeshing has already been applied to the server + // that executed the request. + if (SystemUtilities.GetCurrentTrustLevel() == AspNetHostingPermissionLevel.Unrestricted) + { + //we can only check this in full trust. if it's in medium trust we'll just end up with + // the server refreshing it's cache twice. + if (HttpRuntime.AppDomainAppId == appId) + { + return; + } + } + //only execute distinct instructions - no sense in running the same one. foreach (var instruction in instructions.Distinct()) {