Fix CacheRefresher and DistributedCache
This commit is contained in:
@@ -1,21 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Web.Cache;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Tests.Cache
|
||||
{
|
||||
[TestFixture]
|
||||
[UmbracoTest(WithApplication = true)]
|
||||
public class CacheRefresherEventHandlerTests : UmbracoTestBase
|
||||
public class DistributedCacheBinderTests : UmbracoTestBase
|
||||
{
|
||||
[Test]
|
||||
public void Can_Find_All_Event_Handlers()
|
||||
@@ -114,7 +116,7 @@ namespace Umbraco.Tests.Cache
|
||||
var ok = true;
|
||||
foreach (var definition in definitions)
|
||||
{
|
||||
var found = CacheRefresherComponent.FindHandler(definition);
|
||||
var found = DistributedCacheBinder.FindHandler(definition);
|
||||
if (found == null)
|
||||
{
|
||||
Console.WriteLine("Couldn't find method for " + definition.EventName + " on " + definition.Sender.GetType());
|
||||
@@ -123,5 +125,35 @@ namespace Umbraco.Tests.Cache
|
||||
}
|
||||
Assert.IsTrue(ok, "see log for details");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanHandleEvent()
|
||||
{
|
||||
// refreshers.HandleEvents wants a UmbracoContext
|
||||
// which wants an HttpContext, which we build using a SimpleWorkerRequest
|
||||
// which requires these to be non-null
|
||||
var domain = Thread.GetDomain();
|
||||
if (domain.GetData(".appPath") == null)
|
||||
domain.SetData(".appPath", "");
|
||||
if (domain.GetData(".appVPath") == null)
|
||||
domain.SetData(".appVPath", "");
|
||||
|
||||
// refreshers.HandleEvents wants a UmbracoContext
|
||||
// which wants these
|
||||
Container.RegisterSingleton(_ => Mock.Of<IPublishedSnapshotService>());
|
||||
Container.RegisterCollectionBuilder<UrlProviderCollectionBuilder>();
|
||||
|
||||
// create some event definitions
|
||||
var definitions = new IEventDefinition[]
|
||||
{
|
||||
// works because that event definition maps to an empty handler
|
||||
new EventDefinition<IContentTypeService, SaveEventArgs<IContentType>>(null, Current.Services.ContentTypeService, new SaveEventArgs<IContentType>(Enumerable.Empty<IContentType>()), "Saved"),
|
||||
|
||||
};
|
||||
|
||||
// just assert it does not throw
|
||||
var refreshers = new DistributedCacheBinder(null, null);
|
||||
refreshers.HandleEvents(definitions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,19 +2,17 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LightInject;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.Sync;
|
||||
using Umbraco.Tests.Cache.DistributedCache;
|
||||
using Umbraco.Tests.Services;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
using Umbraco.Tests.TestHelpers.Stubs;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Web.Cache;
|
||||
using static Umbraco.Tests.Cache.DistributedCache.DistributedCacheTests;
|
||||
@@ -34,8 +32,8 @@ namespace Umbraco.Tests.Integration
|
||||
{
|
||||
base.SetUp();
|
||||
|
||||
_h1 = new CacheRefresherComponent(true);
|
||||
_h1.Initialize(new DistributedCache());
|
||||
_h1 = new DistributedCacheBinder(new DistributedCache(), Mock.Of<ILogger>());
|
||||
_h1.BindEvents(true);
|
||||
|
||||
_events = new List<EventInstance>();
|
||||
|
||||
@@ -76,7 +74,7 @@ namespace Umbraco.Tests.Integration
|
||||
{
|
||||
base.TearDown();
|
||||
|
||||
_h1?.Unbind();
|
||||
_h1?.UnbindEvents();
|
||||
|
||||
// clear ALL events
|
||||
|
||||
@@ -86,7 +84,7 @@ namespace Umbraco.Tests.Integration
|
||||
ContentCacheRefresher.CacheUpdated -= ContentCacheUpdated;
|
||||
}
|
||||
|
||||
private CacheRefresherComponent _h1;
|
||||
private DistributedCacheBinder _h1;
|
||||
private IList<EventInstance> _events;
|
||||
private int _msgCount;
|
||||
private IContentType _contentType;
|
||||
|
||||
@@ -11,6 +11,7 @@ using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
@@ -36,7 +37,7 @@ namespace Umbraco.Tests.Scoping
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)]
|
||||
public class ScopedNuCacheTests : TestWithDatabaseBase
|
||||
{
|
||||
private CacheRefresherComponent _cacheRefresher;
|
||||
private DistributedCacheBinder _distributedCacheBinder;
|
||||
|
||||
protected override void Compose()
|
||||
{
|
||||
@@ -56,8 +57,8 @@ namespace Umbraco.Tests.Scoping
|
||||
{
|
||||
base.TearDown();
|
||||
|
||||
_cacheRefresher?.Unbind();
|
||||
_cacheRefresher = null;
|
||||
_distributedCacheBinder?.UnbindEvents();
|
||||
_distributedCacheBinder = null;
|
||||
|
||||
_onPublishedAssertAction = null;
|
||||
ContentService.Published -= OnPublishedAssert;
|
||||
@@ -129,8 +130,8 @@ namespace Umbraco.Tests.Scoping
|
||||
var umbracoContext = GetUmbracoContextNu("http://example.com/", setSingleton: true);
|
||||
|
||||
// wire cache refresher
|
||||
_cacheRefresher = new CacheRefresherComponent(true);
|
||||
_cacheRefresher.Initialize(new DistributedCache());
|
||||
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<ILogger>());
|
||||
_distributedCacheBinder.BindEvents(true);
|
||||
|
||||
// create document type, document
|
||||
var contentType = new ContentType(-1) { Alias = "CustomDocument", Name = "Custom Document" };
|
||||
|
||||
@@ -13,6 +13,7 @@ using Umbraco.Web.Cache;
|
||||
using LightInject;
|
||||
using Moq;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Sync;
|
||||
|
||||
namespace Umbraco.Tests.Scoping
|
||||
@@ -21,7 +22,7 @@ namespace Umbraco.Tests.Scoping
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, WithApplication = true)]
|
||||
public class ScopedRepositoryTests : TestWithDatabaseBase
|
||||
{
|
||||
private CacheRefresherComponent _cacheRefresher;
|
||||
private DistributedCacheBinder _distributedCacheBinder;
|
||||
|
||||
protected override void Compose()
|
||||
{
|
||||
@@ -52,8 +53,8 @@ namespace Umbraco.Tests.Scoping
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
_cacheRefresher?.Unbind();
|
||||
_cacheRefresher = null;
|
||||
_distributedCacheBinder?.UnbindEvents();
|
||||
_distributedCacheBinder = null;
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
@@ -76,8 +77,8 @@ namespace Umbraco.Tests.Scoping
|
||||
// get user again - else we'd modify the one that's in the cache
|
||||
user = service.GetUserById(user.Id);
|
||||
|
||||
_cacheRefresher = new CacheRefresherComponent(true);
|
||||
_cacheRefresher.Initialize(new DistributedCache());
|
||||
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<ILogger>());
|
||||
_distributedCacheBinder.BindEvents(true);
|
||||
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
using (var scope = scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped))
|
||||
@@ -157,8 +158,8 @@ namespace Umbraco.Tests.Scoping
|
||||
Assert.AreEqual(lang.Id, globalCached.Id);
|
||||
Assert.AreEqual("fr-FR", globalCached.IsoCode);
|
||||
|
||||
_cacheRefresher = new CacheRefresherComponent(true);
|
||||
_cacheRefresher.Initialize(new DistributedCache());
|
||||
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<ILogger>());
|
||||
_distributedCacheBinder.BindEvents(true);
|
||||
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
using (var scope = scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped))
|
||||
@@ -249,8 +250,8 @@ namespace Umbraco.Tests.Scoping
|
||||
Assert.AreEqual(item.Id, globalCached.Id);
|
||||
Assert.AreEqual("item-key", globalCached.ItemKey);
|
||||
|
||||
_cacheRefresher = new CacheRefresherComponent(true);
|
||||
_cacheRefresher.Initialize(new DistributedCache());
|
||||
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<ILogger>());
|
||||
_distributedCacheBinder.BindEvents(true);
|
||||
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
using (var scope = scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped))
|
||||
|
||||
@@ -7,6 +7,7 @@ using LightInject;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
@@ -23,7 +24,7 @@ namespace Umbraco.Tests.Scoping
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)]
|
||||
public class ScopedXmlTests : TestWithDatabaseBase
|
||||
{
|
||||
private CacheRefresherComponent _cacheRefresher;
|
||||
private DistributedCacheBinder _distributedCacheBinder;
|
||||
|
||||
protected override void Compose()
|
||||
{
|
||||
@@ -42,8 +43,8 @@ namespace Umbraco.Tests.Scoping
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
_cacheRefresher?.Unbind();
|
||||
_cacheRefresher = null;
|
||||
_distributedCacheBinder?.UnbindEvents();
|
||||
_distributedCacheBinder = null;
|
||||
|
||||
_onPublishedAssertAction = null;
|
||||
ContentService.Published -= OnPublishedAssert;
|
||||
@@ -90,8 +91,8 @@ namespace Umbraco.Tests.Scoping
|
||||
var item = new Content("name", -1, contentType);
|
||||
|
||||
// wire cache refresher
|
||||
_cacheRefresher = new CacheRefresherComponent(true);
|
||||
_cacheRefresher.Initialize(new DistributedCache());
|
||||
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<ILogger>());
|
||||
_distributedCacheBinder.BindEvents(true);
|
||||
|
||||
// check xml in context = "before"
|
||||
var xml = XmlInContext;
|
||||
@@ -209,8 +210,8 @@ namespace Umbraco.Tests.Scoping
|
||||
Current.Services.ContentTypeService.Save(contentType);
|
||||
|
||||
// wire cache refresher
|
||||
_cacheRefresher = new CacheRefresherComponent(true);
|
||||
_cacheRefresher.Initialize(new DistributedCache());
|
||||
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<ILogger>());
|
||||
_distributedCacheBinder.BindEvents(true);
|
||||
|
||||
// check xml in context = "before"
|
||||
var xml = XmlInContext;
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.4.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Cache\CacheRefresherComponentTests.cs" />
|
||||
<Compile Include="Cache\DistributedCacheBinderTests.cs" />
|
||||
<Compile Include="Cache\RefresherTests.cs" />
|
||||
<Compile Include="Cache\SnapDictionaryTests.cs" />
|
||||
<Compile Include="Clr\ReflectionUtilitiesTests.cs" />
|
||||
|
||||
85
src/Umbraco.Web/Cache/DistributedCacheBinder.cs
Normal file
85
src/Umbraco.Web/Cache/DistributedCacheBinder.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Web.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Default <see cref="IDistributedCacheBinder"/> implementation.
|
||||
/// </summary>
|
||||
public partial class DistributedCacheBinder : IDistributedCacheBinder
|
||||
{
|
||||
private static readonly ConcurrentDictionary<string, MethodInfo> FoundHandlers = new ConcurrentDictionary<string, MethodInfo>();
|
||||
private readonly DistributedCache _distributedCache;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DistributedCacheBinder"/> class.
|
||||
/// </summary>
|
||||
/// <param name="distributedCache"></param>
|
||||
/// <param name="logger"></param>
|
||||
public DistributedCacheBinder(DistributedCache distributedCache, ILogger logger)
|
||||
{
|
||||
_distributedCache = distributedCache;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
// internal for tests
|
||||
internal static MethodInfo FindHandler(IEventDefinition eventDefinition)
|
||||
{
|
||||
var name = eventDefinition.Sender.GetType().Name + "_" + eventDefinition.EventName;
|
||||
|
||||
return FoundHandlers.GetOrAdd(name, n => CandidateHandlers.Value.FirstOrDefault(x => x.Name == n));
|
||||
}
|
||||
|
||||
private static readonly Lazy<MethodInfo[]> CandidateHandlers = new Lazy<MethodInfo[]>(() =>
|
||||
{
|
||||
var underscore = new[] { '_' };
|
||||
|
||||
return typeof(DistributedCacheBinder)
|
||||
.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Select(x =>
|
||||
{
|
||||
if (x.Name.Contains("_") == false) return null;
|
||||
|
||||
var parts = x.Name.Split(underscore, StringSplitOptions.RemoveEmptyEntries).Length;
|
||||
if (parts != 2) return null;
|
||||
|
||||
var parameters = x.GetParameters();
|
||||
if (parameters.Length != 2) return null;
|
||||
if (typeof(EventArgs).IsAssignableFrom(parameters[1].ParameterType) == false) return null;
|
||||
return x;
|
||||
})
|
||||
.WhereNotNull()
|
||||
.ToArray();
|
||||
});
|
||||
|
||||
/// <inheritdoc />
|
||||
public void HandleEvents(IEnumerable<IEventDefinition> events)
|
||||
{
|
||||
// ensure we run with an UmbracoContext, because this may run in a background task,
|
||||
// yet developers may be using the 'current' UmbracoContext in the event handlers
|
||||
using (UmbracoContext.EnsureContext())
|
||||
{
|
||||
foreach (var e in events)
|
||||
{
|
||||
var handler = FindHandler(e);
|
||||
if (handler == null)
|
||||
{
|
||||
// fixme - should this be fatal (ie, an exception)?
|
||||
var name = e.Sender.GetType().Name + "_" + e.EventName;
|
||||
_logger.Warn<DistributedCacheBinder>("Dropping event {EventName} because no corresponding handler was found.", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
handler.Invoke(this, new[] { e.Sender, e.Args });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/Umbraco.Web/Cache/DistributedCacheBinderComponent.cs
Normal file
24
src/Umbraco.Web/Cache/DistributedCacheBinderComponent.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Components;
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Web.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Installs listeners on service events in order to refresh our caches.
|
||||
/// </summary>
|
||||
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
|
||||
[RequiredComponent(typeof(IUmbracoCoreComponent))] // runs before every other IUmbracoCoreComponent!
|
||||
public class DistributedCacheBinderComponent : UmbracoComponentBase, IUmbracoCoreComponent
|
||||
{
|
||||
public override void Compose(Composition composition)
|
||||
{
|
||||
composition.Container.RegisterSingleton<IDistributedCacheBinder, DistributedCacheBinder>();
|
||||
}
|
||||
|
||||
public void Initialize(IDistributedCacheBinder distributedCacheBinder)
|
||||
{
|
||||
distributedCacheBinder.BindEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Umbraco.Core;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Web;
|
||||
using System.Web.Hosting;
|
||||
using Umbraco.Core.Components;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Services.Changes;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Web.Services;
|
||||
using LightInject;
|
||||
using ApplicationTree = Umbraco.Core.Models.ApplicationTree;
|
||||
|
||||
namespace Umbraco.Web.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Installs listeners on service events in order to refresh our caches.
|
||||
/// Default <see cref="IDistributedCacheBinder"/> implementation.
|
||||
/// </summary>
|
||||
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
|
||||
[RequiredComponent(typeof(IUmbracoCoreComponent))] // runs before every other IUmbracoCoreComponent!
|
||||
public class CacheRefresherComponent : UmbracoComponentBase, IUmbracoCoreComponent
|
||||
public partial class DistributedCacheBinder
|
||||
{
|
||||
private static readonly ConcurrentDictionary<string, MethodInfo> FoundHandlers = new ConcurrentDictionary<string, MethodInfo>();
|
||||
private DistributedCache _distributedCache;
|
||||
private List<Action> _unbinders;
|
||||
|
||||
public CacheRefresherComponent()
|
||||
{ }
|
||||
private void Bind(Action binder, Action unbinder)
|
||||
{
|
||||
// bind now
|
||||
binder();
|
||||
|
||||
// for tests
|
||||
public CacheRefresherComponent(bool supportUnbinding)
|
||||
// and register unbinder for later, if needed
|
||||
_unbinders?.Add(unbinder);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void UnbindEvents()
|
||||
{
|
||||
if (_unbinders == null)
|
||||
throw new NotSupportedException();
|
||||
foreach (var unbinder in _unbinders)
|
||||
unbinder();
|
||||
_unbinders = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void BindEvents(bool supportUnbinding = false)
|
||||
{
|
||||
if (supportUnbinding)
|
||||
_unbinders = new List<Action>();
|
||||
}
|
||||
|
||||
public void Initialize(DistributedCache distributedCache)
|
||||
{
|
||||
Current.Logger.Info<CacheRefresherComponent>("Initializing Umbraco internal event handlers for cache refreshing.");
|
||||
|
||||
_distributedCache = distributedCache;
|
||||
_logger.Info<DistributedCacheBinderComponent>("Initializing Umbraco internal event handlers for cache refreshing.");
|
||||
|
||||
// bind to application tree events
|
||||
Bind(() => ApplicationTreeService.Deleted += ApplicationTreeService_Deleted,
|
||||
@@ -170,74 +164,6 @@ namespace Umbraco.Web.Cache
|
||||
() => RelationService.DeletedRelationType -= RelationService_DeletedRelationType);
|
||||
}
|
||||
|
||||
#region Events binding and handling
|
||||
|
||||
private void Bind(Action binder, Action unbinder)
|
||||
{
|
||||
// bind now
|
||||
binder();
|
||||
|
||||
// and register unbinder for later, if needed
|
||||
_unbinders?.Add(unbinder);
|
||||
}
|
||||
|
||||
// for tests
|
||||
internal void Unbind()
|
||||
{
|
||||
if (_unbinders == null)
|
||||
throw new NotSupportedException();
|
||||
foreach (var unbinder in _unbinders)
|
||||
unbinder();
|
||||
_unbinders = null;
|
||||
}
|
||||
|
||||
internal static MethodInfo FindHandler(IEventDefinition eventDefinition)
|
||||
{
|
||||
var name = eventDefinition.Sender.GetType().Name + "_" + eventDefinition.EventName;
|
||||
|
||||
return FoundHandlers.GetOrAdd(name, n => CandidateHandlers.Value.FirstOrDefault(x => x.Name == n));
|
||||
}
|
||||
|
||||
private static readonly Lazy<MethodInfo[]> CandidateHandlers = new Lazy<MethodInfo[]>(() =>
|
||||
{
|
||||
var underscore = new[] { '_' };
|
||||
|
||||
return typeof(CacheRefresherComponent)
|
||||
.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Select(x =>
|
||||
{
|
||||
if (x.Name.Contains("_") == false) return null;
|
||||
|
||||
var parts = x.Name.Split(underscore, StringSplitOptions.RemoveEmptyEntries).Length;
|
||||
if (parts != 2) return null;
|
||||
|
||||
var parameters = x.GetParameters();
|
||||
if (parameters.Length != 2) return null;
|
||||
if (typeof(EventArgs).IsAssignableFrom(parameters[1].ParameterType) == false) return null;
|
||||
return x;
|
||||
})
|
||||
.WhereNotNull()
|
||||
.ToArray();
|
||||
});
|
||||
|
||||
internal static void HandleEvents(IEnumerable<IEventDefinition> events)
|
||||
{
|
||||
// ensure we run with an UmbracoContext, because this may run in a background task,
|
||||
// yet developers may be using the 'current' UmbracoContext in the event handlers
|
||||
using (UmbracoContext.EnsureContext())
|
||||
{
|
||||
foreach (var e in events)
|
||||
{
|
||||
var handler = FindHandler(e);
|
||||
if (handler == null) continue;
|
||||
|
||||
handler.Invoke(null, new[] { e.Sender, e.Args });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PublicAccessService
|
||||
|
||||
private void PublicAccessService_Saved(IPublicAccessService sender, SaveEventArgs<PublicAccessEntry> e)
|
||||
@@ -264,7 +190,8 @@ namespace Umbraco.Web.Cache
|
||||
/// case then we need to clear all user permissions cache.
|
||||
/// </remarks>
|
||||
private void ContentService_Copied(IContentService sender, CopyEventArgs<IContent> e)
|
||||
{ }
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles cache refreshing for when content is saved (not published)
|
||||
@@ -276,7 +203,8 @@ namespace Umbraco.Web.Cache
|
||||
/// stay up-to-date for unpublished content.
|
||||
/// </remarks>
|
||||
private void ContentService_Saved(IContentService sender, SaveEventArgs<IContent> e)
|
||||
{ }
|
||||
{
|
||||
}
|
||||
|
||||
private void ContentService_Changed(IContentService sender, TreeChange<IContent>.EventArgs args)
|
||||
{
|
||||
@@ -324,12 +252,12 @@ namespace Umbraco.Web.Cache
|
||||
|
||||
#region Application event handlers
|
||||
|
||||
private void SectionService_New(Section sender, EventArgs e)
|
||||
private void SectionService_New(ISectionService sender, EventArgs e)
|
||||
{
|
||||
_distributedCache.RefreshAllApplicationCache();
|
||||
}
|
||||
|
||||
private void SectionService_Deleted(Section sender, EventArgs e)
|
||||
private void SectionService_Deleted(ISectionService sender, EventArgs e)
|
||||
{
|
||||
_distributedCache.RefreshAllApplicationCache();
|
||||
}
|
||||
@@ -439,7 +367,8 @@ namespace Umbraco.Web.Cache
|
||||
|
||||
#region UserService
|
||||
|
||||
static void UserService_UserGroupPermissionsAssigned(IUserService sender, SaveEventArgs<EntityPermission> e)
|
||||
// fixme STATIC??
|
||||
private void UserService_UserGroupPermissionsAssigned(IUserService sender, SaveEventArgs<EntityPermission> e)
|
||||
{
|
||||
//TODO: Not sure if we need this yet depends if we start caching permissions
|
||||
//var groupIds = e.SavedEntities.Select(x => x.UserGroupId).Distinct();
|
||||
@@ -568,6 +497,7 @@ namespace Umbraco.Web.Cache
|
||||
_distributedCache.RemoveMemberGroupCache(m.Id);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region RelationType
|
||||
34
src/Umbraco.Web/Cache/IDistributedCacheBinder.cs
Normal file
34
src/Umbraco.Web/Cache/IDistributedCacheBinder.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
|
||||
namespace Umbraco.Web.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Binds events to the distributed cache.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Use <see cref="BindEvents"/> to bind actual events, eg <see cref="ContentService.Saved"/>, to
|
||||
/// the distributed cache, so that the proper refresh operations are executed when these events trigger.</para>
|
||||
/// <para>Use <see cref="HandleEvents"/> to handle events that have not actually triggered, but have
|
||||
/// been queued, so that the proper refresh operations are also executed.</para>
|
||||
/// </remarks>
|
||||
public interface IDistributedCacheBinder
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles events from definitions.
|
||||
/// </summary>
|
||||
void HandleEvents(IEnumerable<IEventDefinition> events);
|
||||
|
||||
/// <summary>
|
||||
/// Binds actual events to the distributed cache.
|
||||
/// </summary>
|
||||
/// <param name="enableUnbinding">A value indicating whether to support unbinding the events.</param>
|
||||
void BindEvents(bool enableUnbinding = false);
|
||||
|
||||
/// <summary>
|
||||
/// Unbinds bounded events.
|
||||
/// </summary>
|
||||
void UnbindEvents();
|
||||
}
|
||||
}
|
||||
@@ -200,7 +200,7 @@ namespace Umbraco.Web.Services
|
||||
}, true);
|
||||
|
||||
//raise event
|
||||
OnNew(new Section(name, alias, sortOrder), new EventArgs());
|
||||
OnNew(this /*new Section(name, alias, sortOrder)*/, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ namespace Umbraco.Web.Services
|
||||
}, true);
|
||||
|
||||
//raise event
|
||||
OnDeleted(section, new EventArgs());
|
||||
OnDeleted(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,8 +262,8 @@ namespace Umbraco.Web.Services
|
||||
return tmp;
|
||||
}
|
||||
|
||||
internal static event TypedEventHandler<Section, EventArgs> Deleted;
|
||||
private static void OnDeleted(Section app, EventArgs args)
|
||||
internal static event TypedEventHandler<ISectionService, EventArgs> Deleted;
|
||||
private static void OnDeleted(ISectionService app, EventArgs args)
|
||||
{
|
||||
if (Deleted != null)
|
||||
{
|
||||
@@ -271,8 +271,8 @@ namespace Umbraco.Web.Services
|
||||
}
|
||||
}
|
||||
|
||||
internal static event TypedEventHandler<Section, EventArgs> New;
|
||||
private static void OnNew(Section app, EventArgs args)
|
||||
internal static event TypedEventHandler<ISectionService, EventArgs> New;
|
||||
private static void OnNew(ISectionService app, EventArgs args)
|
||||
{
|
||||
if (New != null)
|
||||
{
|
||||
|
||||
@@ -108,7 +108,10 @@
|
||||
<Compile Include="AppBuilderExtensions.cs" />
|
||||
<Compile Include="AreaRegistrationContextExtensions.cs" />
|
||||
<Compile Include="AspNetHttpContextAccessor.cs" />
|
||||
<Compile Include="Cache\DistributedCacheBinder.cs" />
|
||||
<Compile Include="Cache\DistributedCacheBinder_Handlers.cs" />
|
||||
<Compile Include="Cache\ContentCacheRefresher.cs" />
|
||||
<Compile Include="Cache\IDistributedCacheBinder.cs" />
|
||||
<Compile Include="Cache\UserGroupCacheRefresher.cs" />
|
||||
<Compile Include="Components\BackOfficeUserAuditEventsComponent.cs" />
|
||||
<Compile Include="ContentApps\ListViewContentAppFactory.cs" />
|
||||
@@ -652,7 +655,7 @@
|
||||
<Compile Include="Cache\DictionaryCacheRefresher.cs" />
|
||||
<Compile Include="Cache\DistributedCache.cs" />
|
||||
<Compile Include="Cache\DistributedCacheExtensions.cs" />
|
||||
<Compile Include="Cache\CacheRefresherComponent.cs" />
|
||||
<Compile Include="Cache\DistributedCacheBinderComponent.cs" />
|
||||
<Compile Include="Cache\DomainCacheRefresher.cs" />
|
||||
<Compile Include="Cache\LanguageCacheRefresher.cs" />
|
||||
<Compile Include="Cache\MacroCacheRefresher.cs" />
|
||||
|
||||
Reference in New Issue
Block a user