2014-04-23 20:19:36 +10:00
using System ;
2017-02-06 17:26:06 +11:00
using System.Collections.Concurrent ;
2015-03-31 17:06:13 +11:00
using System.Collections.Generic ;
2017-05-01 21:10:22 +10:00
using System.IO ;
2013-03-16 08:47:55 +06:00
using Umbraco.Core ;
2014-02-17 17:45:59 +11:00
using Umbraco.Core.Events ;
2013-03-16 08:47:55 +06:00
using Umbraco.Core.Models ;
2014-02-17 17:45:59 +11:00
using Umbraco.Core.Models.Membership ;
using Umbraco.Core.Persistence.Repositories ;
2013-02-06 09:53:13 +06:00
using Umbraco.Core.Services ;
2013-02-12 04:13:29 +06:00
using umbraco.BusinessLogic ;
2013-02-06 09:53:13 +06:00
using umbraco.cms.businesslogic ;
using System.Linq ;
2017-02-06 17:26:06 +11:00
using System.Reflection ;
2017-05-01 21:10:22 +10:00
using System.Web ;
using System.Web.Hosting ;
using Umbraco.Core.Configuration ;
2015-07-08 16:54:38 +02:00
using Umbraco.Core.Logging ;
2016-11-24 17:37:20 +01:00
using Umbraco.Core.ObjectResolution ;
2015-03-30 17:36:54 +11:00
using Umbraco.Core.Publishing ;
2017-05-01 21:10:22 +10:00
using Umbraco.Web.Routing ;
using Umbraco.Web.Security ;
2013-07-09 11:47:46 +10:00
using Content = Umbraco . Core . Models . Content ;
2013-07-02 17:47:20 +10:00
using ApplicationTree = Umbraco . Core . Models . ApplicationTree ;
2014-02-17 17:45:59 +11:00
using DeleteEventArgs = umbraco . cms . businesslogic . DeleteEventArgs ;
2013-02-06 09:53:13 +06:00
namespace Umbraco.Web.Cache
{
/// <summary>
2013-02-07 04:45:05 +06:00
/// Class which listens to events on business level objects in order to invalidate the cache amongst servers when data changes
2013-02-06 09:53:13 +06:00
/// </summary>
2016-11-28 09:38:50 +01:00
[Weight(int.MinValue)]
2013-02-07 04:45:05 +06:00
public class CacheRefresherEventHandler : ApplicationEventHandler
2013-02-06 09:53:13 +06:00
{
2017-02-17 09:54:50 +01:00
public CacheRefresherEventHandler ()
{ }
public CacheRefresherEventHandler ( bool supportUnbinding )
{
if ( supportUnbinding )
_unbinders = new List < Action >();
}
2013-02-06 09:53:13 +06:00
protected override void ApplicationStarted ( UmbracoApplicationBase umbracoApplication , ApplicationContext applicationContext )
2015-07-08 16:54:38 +02:00
{
LogHelper . Info < CacheRefresherEventHandler >( "Initializing Umbraco internal event handlers for cache refreshing" );
2017-02-17 09:54:50 +01:00
// bind to application tree events
Bind (() => ApplicationTreeService . Deleted += ApplicationTreeService_Deleted ,
() => ApplicationTreeService . Deleted -= ApplicationTreeService_Deleted );
Bind (() => ApplicationTreeService . Updated += ApplicationTreeService_Updated ,
() => ApplicationTreeService . Updated -= ApplicationTreeService_Updated );
Bind (() => ApplicationTreeService . New += ApplicationTreeService_New ,
() => ApplicationTreeService . New -= ApplicationTreeService_New );
2013-04-04 21:57:41 +06:00
2017-02-17 09:54:50 +01:00
// bind to application events
Bind (() => SectionService . Deleted += SectionService_Deleted ,
() => SectionService . Deleted -= SectionService_Deleted );
Bind (() => SectionService . New += SectionService_New ,
() => SectionService . New -= SectionService_New );
2017-05-04 19:16:52 +10:00
2017-06-30 18:14:44 +10:00
// bind to user and user / user group events
2017-05-11 20:51:31 +10:00
Bind (() => UserService . SavedUserGroup += UserService_SavedUserGroup ,
() => UserService . SavedUserGroup -= UserService_SavedUserGroup );
Bind (() => UserService . DeletedUserGroup += UserService_DeletedUserGroup ,
() => UserService . DeletedUserGroup -= UserService_DeletedUserGroup );
2017-02-17 09:54:50 +01:00
Bind (() => UserService . SavedUser += UserService_SavedUser ,
() => UserService . SavedUser -= UserService_SavedUser );
Bind (() => UserService . DeletedUser += UserService_DeletedUser ,
() => UserService . DeletedUser -= UserService_DeletedUser );
2017-07-13 18:47:10 +10:00
Bind (() => UserService . UserGroupPermissionsAssigned += UserService_UserGroupPermissionsAssigned ,
() => UserService . UserGroupPermissionsAssigned -= UserService_UserGroupPermissionsAssigned );
2013-03-22 05:04:32 +06:00
2017-02-17 09:54:50 +01:00
// bind to dictionary events
Bind (() => LocalizationService . DeletedDictionaryItem += LocalizationService_DeletedDictionaryItem ,
() => LocalizationService . DeletedDictionaryItem -= LocalizationService_DeletedDictionaryItem );
Bind (() => LocalizationService . SavedDictionaryItem += LocalizationService_SavedDictionaryItem ,
() => LocalizationService . SavedDictionaryItem -= LocalizationService_SavedDictionaryItem );
2013-03-23 01:59:25 +06:00
2017-02-17 09:54:50 +01:00
// bind to data type events
Bind (() => DataTypeService . Deleted += DataTypeService_Deleted ,
() => DataTypeService . Deleted -= DataTypeService_Deleted );
Bind (() => DataTypeService . Saved += DataTypeService_Saved ,
() => DataTypeService . Saved -= DataTypeService_Saved );
2013-03-23 01:59:25 +06:00
2017-02-17 09:54:50 +01:00
// bind to stylesheet events
Bind (() => FileService . SavedStylesheet += FileService_SavedStylesheet ,
() => FileService . SavedStylesheet -= FileService_SavedStylesheet );
Bind (() => FileService . DeletedStylesheet += FileService_DeletedStylesheet ,
() => FileService . DeletedStylesheet -= FileService_DeletedStylesheet );
2015-05-18 16:06:22 +10:00
2017-02-17 09:54:50 +01:00
// bind to domain events
Bind (() => DomainService . Saved += DomainService_Saved ,
() => DomainService . Saved -= DomainService_Saved );
Bind (() => DomainService . Deleted += DomainService_Deleted ,
() => DomainService . Deleted -= DomainService_Deleted );
2013-03-22 05:04:32 +06:00
2017-02-17 09:54:50 +01:00
// bind to language events
Bind (() => LocalizationService . SavedLanguage += LocalizationService_SavedLanguage ,
() => LocalizationService . SavedLanguage -= LocalizationService_SavedLanguage );
Bind (() => LocalizationService . DeletedLanguage += LocalizationService_DeletedLanguage ,
() => LocalizationService . DeletedLanguage -= LocalizationService_DeletedLanguage );
2013-03-22 01:49:34 +06:00
2017-02-17 09:54:50 +01:00
// bind to content type events
Bind (() => ContentTypeService . SavedContentType += ContentTypeService_SavedContentType ,
() => ContentTypeService . SavedContentType -= ContentTypeService_SavedContentType );
Bind (() => ContentTypeService . SavedMediaType += ContentTypeService_SavedMediaType ,
() => ContentTypeService . SavedMediaType -= ContentTypeService_SavedMediaType );
Bind (() => ContentTypeService . DeletedContentType += ContentTypeService_DeletedContentType ,
() => ContentTypeService . DeletedContentType -= ContentTypeService_DeletedContentType );
Bind (() => ContentTypeService . DeletedMediaType += ContentTypeService_DeletedMediaType ,
() => ContentTypeService . DeletedMediaType -= ContentTypeService_DeletedMediaType );
Bind (() => MemberTypeService . Saved += MemberTypeService_Saved ,
() => MemberTypeService . Saved -= MemberTypeService_Saved );
Bind (() => MemberTypeService . Deleted += MemberTypeService_Deleted ,
2017-07-13 18:47:10 +10:00
() => MemberTypeService . Deleted -= MemberTypeService_Deleted );
2017-07-18 13:31:04 +10:00
2017-07-13 18:47:10 +10:00
2017-02-17 09:54:50 +01:00
// bind to template events
Bind (() => FileService . SavedTemplate += FileService_SavedTemplate ,
() => FileService . SavedTemplate -= FileService_SavedTemplate );
Bind (() => FileService . DeletedTemplate += FileService_DeletedTemplate ,
() => FileService . DeletedTemplate -= FileService_DeletedTemplate );
2013-03-22 00:49:07 +06:00
2017-02-17 09:54:50 +01:00
// bind to macro events
Bind (() => MacroService . Saved += MacroService_Saved ,
() => MacroService . Saved -= MacroService_Saved );
Bind (() => MacroService . Deleted += MacroService_Deleted ,
() => MacroService . Deleted -= MacroService_Deleted );
2013-03-22 00:35:15 +06:00
2017-02-17 09:54:50 +01:00
// bind to member events
Bind (() => MemberService . Saved += MemberService_Saved ,
() => MemberService . Saved -= MemberService_Saved );
Bind (() => MemberService . Deleted += MemberService_Deleted ,
() => MemberService . Deleted -= MemberService_Deleted );
Bind (() => MemberGroupService . Saved += MemberGroupService_Saved ,
() => MemberGroupService . Saved -= MemberGroupService_Saved );
Bind (() => MemberGroupService . Deleted += MemberGroupService_Deleted ,
() => MemberGroupService . Deleted -= MemberGroupService_Deleted );
2013-03-22 00:35:15 +06:00
2017-02-17 09:54:50 +01:00
// bind to media events
Bind (() => MediaService . Saved += MediaService_Saved ,
() => MediaService . Saved -= MediaService_Saved );
Bind (() => MediaService . Deleted += MediaService_Deleted ,
() => MediaService . Deleted -= MediaService_Deleted );
Bind (() => MediaService . Moved += MediaService_Moved ,
() => MediaService . Moved -= MediaService_Moved );
Bind (() => MediaService . Trashed += MediaService_Trashed ,
() => MediaService . Trashed -= MediaService_Trashed );
Bind (() => MediaService . EmptiedRecycleBin += MediaService_EmptiedRecycleBin ,
() => MediaService . EmptiedRecycleBin -= MediaService_EmptiedRecycleBin );
2013-03-16 08:47:55 +06:00
2017-02-17 09:54:50 +01:00
// bind to content events
// this is for unpublished content syncing across servers (primarily for examine)
Bind (() => ContentService . Saved += ContentService_Saved ,
() => ContentService . Saved -= ContentService_Saved );
Bind (() => ContentService . Deleted += ContentService_Deleted ,
() => ContentService . Deleted -= ContentService_Deleted );
Bind (() => ContentService . Copied += ContentService_Copied ,
() => ContentService . Copied -= ContentService_Copied );
// the Move method of the content service fires Saved/Published events during its
// execution so we don't need to listen to moved - this will probably change in due time
//Bind(() => ContentService.Moved += ContentServiceMoved,
// () => ContentService.Moved -= ContentServiceMoved);
Bind (() => ContentService . Trashed += ContentService_Trashed ,
() => ContentService . Trashed -= ContentService_Trashed );
Bind (() => ContentService . EmptiedRecycleBin += ContentService_EmptiedRecycleBin ,
() => ContentService . EmptiedRecycleBin -= ContentService_EmptiedRecycleBin );
Bind (() => ContentService . Published += ContentService_Published ,
() => ContentService . Published -= ContentService_Published );
Bind (() => ContentService . UnPublished += ContentService_UnPublished ,
() => ContentService . UnPublished -= ContentService_UnPublished );
2013-02-12 04:13:29 +06:00
2017-08-02 16:10:39 +02:00
Bind (() => ContentService . SavedBlueprint += ContentService_SavedBlueprint ,
() => ContentService . SavedBlueprint -= ContentService_SavedBlueprint );
Bind (() => ContentService . DeletedBlueprint += ContentService_DeletedBlueprint ,
() => ContentService . DeletedBlueprint -= ContentService_DeletedBlueprint );
2017-02-17 09:54:50 +01:00
// bind to public access events
Bind (() => PublicAccessService . Saved += PublicAccessService_Saved ,
() => PublicAccessService . Saved -= PublicAccessService_Saved );
Bind (() => PublicAccessService . Deleted += PublicAccessService_Deleted ,
() => PublicAccessService . Deleted -= PublicAccessService_Deleted );
2013-04-04 00:30:28 +06:00
2017-02-17 09:54:50 +01:00
// bind to relation type events
Bind (() => RelationService . SavedRelationType += RelationService_SavedRelationType ,
() => RelationService . SavedRelationType -= RelationService_SavedRelationType );
Bind (() => RelationService . DeletedRelationType += RelationService_DeletedRelationType ,
() => RelationService . DeletedRelationType -= RelationService_DeletedRelationType );
}
2013-04-04 00:30:28 +06:00
2017-02-17 09:54:50 +01:00
private List < Action > _unbinders ;
2013-02-07 05:26:53 +06:00
2017-02-17 09:54:50 +01:00
private void Bind ( Action binder , Action unbinder )
{
// bind now
binder ();
2013-02-07 05:26:53 +06:00
2017-02-17 09:54:50 +01:00
// abd register unbinder for later, if needed
if ( _unbinders == null ) return ;
_unbinders . Add ( unbinder );
2013-02-06 09:53:13 +06:00
}
2016-11-09 13:05:23 +01:00
2017-01-23 17:48:03 +01:00
// for tests
2017-02-17 09:54:50 +01:00
internal void Unbind ()
2017-01-23 17:48:03 +01:00
{
2017-02-17 09:54:50 +01:00
if ( _unbinders == null )
throw new NotSupportedException ();
foreach ( var unbinder in _unbinders )
unbinder ();
_unbinders = null ;
2017-01-23 17:48:03 +01:00
}
2015-03-30 17:36:54 +11:00
#region Publishing
2017-02-14 11:10:09 +01:00
// IPublishingStrategy (obsolete) events are proxied into ContentService, which works fine when
// events are actually raised, but not when they are handled by HandleEvents, so we have to have
// these proxy methods that are *not* registered against any event *but* used by HandleEvents.
2017-02-17 09:54:50 +01:00
// ReSharper disable once UnusedMember.Local
2017-02-14 11:10:09 +01:00
static void PublishingStrategy_UnPublished ( IPublishingStrategy sender , PublishEventArgs < IContent > e )
{
ContentService_UnPublished ( sender , e );
}
2017-02-17 09:54:50 +01:00
// ReSharper disable once UnusedMember.Local
2017-02-14 11:10:09 +01:00
static void PublishingStrategy_Published ( IPublishingStrategy sender , PublishEventArgs < IContent > e )
{
ContentService_Published ( sender , e );
}
2017-02-06 17:26:06 +11:00
static void ContentService_UnPublished ( IPublishingStrategy sender , PublishEventArgs < IContent > e )
2015-03-30 17:36:54 +11:00
{
if ( e . PublishedEntities . Any ())
{
if ( e . PublishedEntities . Count () > 1 )
{
foreach ( var c in e . PublishedEntities )
{
UnPublishSingle ( c );
}
}
else
{
var content = e . PublishedEntities . FirstOrDefault ();
UnPublishSingle ( content );
}
}
}
/// <summary>
/// Refreshes the xml cache for a single node by removing it
/// </summary>
2017-02-06 17:26:06 +11:00
private static void UnPublishSingle ( IContent content )
2015-03-30 17:36:54 +11:00
{
DistributedCache . Instance . RemovePageCache ( content );
}
2017-02-06 17:26:06 +11:00
static void ContentService_Published ( IPublishingStrategy sender , PublishEventArgs < IContent > e )
2015-03-30 17:36:54 +11:00
{
if ( e . PublishedEntities . Any ())
{
if ( e . IsAllRepublished )
{
UpdateEntireCache ();
return ;
}
if ( e . PublishedEntities . Count () > 1 )
{
UpdateMultipleContentCache ( e . PublishedEntities );
}
else
{
var content = e . PublishedEntities . FirstOrDefault ();
UpdateSingleContentCache ( content );
}
}
}
/// <summary>
/// Refreshes the xml cache for all nodes
/// </summary>
2017-02-06 17:26:06 +11:00
private static void UpdateEntireCache ()
2015-03-30 17:36:54 +11:00
{
DistributedCache . Instance . RefreshAllPageCache ();
}
/// <summary>
/// Refreshes the xml cache for nodes in list
/// </summary>
2017-02-06 17:26:06 +11:00
private static void UpdateMultipleContentCache ( IEnumerable < IContent > content )
2015-03-30 17:36:54 +11:00
{
DistributedCache . Instance . RefreshPageCache ( content . ToArray ());
}
/// <summary>
/// Refreshes the xml cache for a single node
/// </summary>
2017-02-06 17:26:06 +11:00
private static void UpdateSingleContentCache ( IContent content )
2015-03-30 17:36:54 +11:00
{
DistributedCache . Instance . RefreshPageCache ( content );
}
#endregion
2014-03-27 14:43:07 +11:00
#region Public access event handlers
2014-03-27 14:28:45 +11:00
2015-01-28 13:16:50 +11:00
static void PublicAccessService_Saved ( IPublicAccessService sender , SaveEventArgs < PublicAccessEntry > e )
2014-03-27 14:43:07 +11:00
{
DistributedCache . Instance . RefreshPublicAccess ();
2015-01-28 13:16:50 +11:00
}
2014-03-27 14:43:07 +11:00
2017-02-06 17:26:06 +11:00
static void PublicAccessService_Deleted ( IPublicAccessService sender , DeleteEventArgs < PublicAccessEntry > e )
2016-01-07 12:18:57 +01:00
{
DistributedCache . Instance . RefreshPublicAccess ();
}
2014-03-27 14:43:07 +11:00
#endregion
2014-03-06 17:50:08 +11:00
2013-07-09 11:47:46 +10:00
#region Content service event handlers
2017-02-06 17:26:06 +11:00
static void ContentService_EmptiedRecycleBin ( IContentService sender , RecycleBinEventArgs e )
2014-04-23 20:19:36 +10:00
{
if ( e . RecycleBinEmptiedSuccessfully && e . IsContentRecycleBin )
{
DistributedCache . Instance . RemoveUnpublishedCachePermanently ( e . Ids . ToArray ());
}
}
2016-11-24 17:37:20 +01:00
2013-07-09 11:47:46 +10:00
/// <summary>
2014-04-23 20:19:36 +10:00
/// Handles cache refreshing for when content is trashed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks>
/// This is for the unpublished page refresher - the entity will be unpublished before being moved to the trash
/// and the unpublished event will take care of remove it from any published caches
/// </remarks>
2017-02-06 17:26:06 +11:00
static void ContentService_Trashed ( IContentService sender , MoveEventArgs < IContent > e )
2014-04-23 20:19:36 +10:00
{
DistributedCache . Instance . RefreshUnpublishedPageCache (
e . MoveInfoCollection . Select ( x => x . Entity ). ToArray ());
}
/// <summary>
/// Handles cache refreshing for when content is copied
2013-07-09 11:47:46 +10:00
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
2014-03-06 17:50:08 +11:00
/// <remarks>
2016-11-24 17:37:20 +01:00
/// When an entity is copied new permissions may be assigned to it based on it's parent, if that is the
2014-03-06 17:50:08 +11:00
/// case then we need to clear all user permissions cache.
/// </remarks>
2017-02-06 17:26:06 +11:00
static void ContentService_Copied ( IContentService sender , CopyEventArgs < IContent > e )
2013-07-09 11:47:46 +10:00
{
2014-04-23 20:19:36 +10:00
//run the un-published cache refresher since copied content is not published
2014-03-06 17:50:08 +11:00
DistributedCache . Instance . RefreshUnpublishedPageCache ( e . Copy );
2013-07-09 11:47:46 +10:00
}
/// <summary>
2014-03-06 17:50:08 +11:00
/// Handles cache refreshing for when content is deleted (not unpublished)
2013-07-09 11:47:46 +10:00
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
2017-02-06 17:26:06 +11:00
static void ContentService_Deleted ( IContentService sender , DeleteEventArgs < IContent > e )
2013-07-09 11:47:46 +10:00
{
2014-03-06 17:50:08 +11:00
DistributedCache . Instance . RemoveUnpublishedPageCache ( e . DeletedEntities . ToArray ());
}
2017-08-02 16:10:39 +02:00
static void ContentService_DeletedBlueprint ( IContentService sender , DeleteEventArgs < IContent > e )
{
DistributedCache . Instance . RemoveUnpublishedPageCache ( e . DeletedEntities . ToArray ());
}
2017-09-08 11:31:04 +10:00
2014-03-06 17:50:08 +11:00
/// <summary>
/// Handles cache refreshing for when content is saved (not published)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks>
2016-11-24 17:37:20 +01:00
/// When an entity is saved we need to notify other servers about the change in order for the Examine indexes to
2017-07-13 11:02:34 +10:00
/// stay up-to-date for unpublished content.
2014-03-06 17:50:08 +11:00
/// </remarks>
2017-02-06 17:26:06 +11:00
static void ContentService_Saved ( IContentService sender , SaveEventArgs < IContent > e )
2014-03-06 17:50:08 +11:00
{
//filter out the entities that have only been saved (not newly published) since
// newly published ones will be synced with the published page cache refresher
var unpublished = e . SavedEntities . Where ( x => x . JustPublished () == false );
//run the un-published cache refresher
DistributedCache . Instance . RefreshUnpublishedPageCache ( unpublished . ToArray ());
}
2017-08-02 16:10:39 +02:00
static void ContentService_SavedBlueprint ( IContentService sender , SaveEventArgs < IContent > e )
{
DistributedCache . Instance . RefreshUnpublishedPageCache ( e . SavedEntities . ToArray ());
}
2014-03-06 17:50:08 +11:00
2013-07-09 11:47:46 +10:00
#endregion
2013-04-04 21:57:41 +06:00
#region ApplicationTree event handlers
2017-02-06 17:26:06 +11:00
static void ApplicationTreeService_New ( ApplicationTree sender , EventArgs e )
2013-04-04 21:57:41 +06:00
{
DistributedCache . Instance . RefreshAllApplicationTreeCache ();
}
2017-02-06 17:26:06 +11:00
static void ApplicationTreeService_Updated ( ApplicationTree sender , EventArgs e )
2013-04-04 21:57:41 +06:00
{
DistributedCache . Instance . RefreshAllApplicationTreeCache ();
}
2017-02-06 17:26:06 +11:00
static void ApplicationTreeService_Deleted ( ApplicationTree sender , EventArgs e )
2013-04-04 21:57:41 +06:00
{
DistributedCache . Instance . RefreshAllApplicationTreeCache ();
2016-11-24 17:37:20 +01:00
}
2013-04-04 21:57:41 +06:00
#endregion
#region Application event handlers
2017-02-06 17:26:06 +11:00
static void SectionService_New ( Section sender , EventArgs e )
2013-04-04 21:57:41 +06:00
{
DistributedCache . Instance . RefreshAllApplicationCache ();
}
2017-02-06 17:26:06 +11:00
static void SectionService_Deleted ( Section sender , EventArgs e )
2013-04-04 21:57:41 +06:00
{
DistributedCache . Instance . RefreshAllApplicationCache ();
2016-11-24 17:37:20 +01:00
}
2013-04-04 21:57:41 +06:00
#endregion
2013-03-23 01:59:25 +06:00
#region Dictionary event handlers
2017-02-06 17:26:06 +11:00
static void LocalizationService_SavedDictionaryItem ( ILocalizationService sender , SaveEventArgs < IDictionaryItem > e )
2013-03-23 01:59:25 +06:00
{
e . SavedEntities . ForEach ( x => DistributedCache . Instance . RefreshDictionaryCache ( x . Id ));
}
2017-02-06 17:26:06 +11:00
static void LocalizationService_DeletedDictionaryItem ( ILocalizationService sender , DeleteEventArgs < IDictionaryItem > e )
2013-03-23 01:59:25 +06:00
{
e . DeletedEntities . ForEach ( x => DistributedCache . Instance . RemoveDictionaryCache ( x . Id ));
}
#endregion
2013-03-22 05:04:32 +06:00
#region DataType event handlers
2017-02-06 17:26:06 +11:00
static void DataTypeService_Saved ( IDataTypeService sender , SaveEventArgs < IDataTypeDefinition > e )
2013-03-22 05:04:32 +06:00
{
2013-05-07 19:37:57 -10:00
e . SavedEntities . ForEach ( x => DistributedCache . Instance . RefreshDataTypeCache ( x ));
2013-03-22 05:04:32 +06:00
}
2017-02-06 17:26:06 +11:00
static void DataTypeService_Deleted ( IDataTypeService sender , DeleteEventArgs < IDataTypeDefinition > e )
2013-03-22 05:04:32 +06:00
{
2013-05-07 19:37:57 -10:00
e . DeletedEntities . ForEach ( x => DistributedCache . Instance . RemoveDataTypeCache ( x ));
2013-03-22 05:04:32 +06:00
}
2016-11-24 17:37:20 +01:00
2013-03-22 05:04:32 +06:00
#endregion
2013-03-22 01:49:34 +06:00
#region Stylesheet and stylesheet property event handlers
2016-11-24 17:37:20 +01:00
2017-02-06 17:26:06 +11:00
static void FileService_DeletedStylesheet ( IFileService sender , DeleteEventArgs < Stylesheet > e )
2013-03-22 01:49:34 +06:00
{
2013-03-23 01:59:25 +06:00
e . DeletedEntities . ForEach ( x => DistributedCache . Instance . RemoveStylesheetCache ( x ));
2013-03-22 01:49:34 +06:00
}
2017-02-06 17:26:06 +11:00
static void FileService_SavedStylesheet ( IFileService sender , SaveEventArgs < Stylesheet > e )
2013-03-22 01:49:34 +06:00
{
2013-03-23 01:59:25 +06:00
e . SavedEntities . ForEach ( x => DistributedCache . Instance . RefreshStylesheetCache ( x ));
2013-03-22 01:49:34 +06:00
}
#endregion
#region Domain event handlers
2015-01-22 12:17:36 +11:00
static void DomainService_Saved ( IDomainService sender , SaveEventArgs < IDomain > e )
2013-03-22 00:49:07 +06:00
{
2015-01-22 12:17:36 +11:00
e . SavedEntities . ForEach ( x => DistributedCache . Instance . RefreshDomainCache ( x ));
2013-03-22 00:49:07 +06:00
}
2015-01-22 12:17:36 +11:00
static void DomainService_Deleted ( IDomainService sender , DeleteEventArgs < IDomain > e )
2013-03-22 00:49:07 +06:00
{
2015-01-22 12:17:36 +11:00
e . DeletedEntities . ForEach ( x => DistributedCache . Instance . RemoveDomainCache ( x ));
2013-03-22 00:49:07 +06:00
}
2013-03-22 01:49:34 +06:00
#endregion
2013-03-22 00:49:07 +06:00
2013-03-22 01:49:34 +06:00
#region Language event handlers
2013-03-22 00:35:15 +06:00
/// <summary>
/// Fires when a langauge is deleted
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
2017-02-06 17:26:06 +11:00
static void LocalizationService_DeletedLanguage ( ILocalizationService sender , DeleteEventArgs < ILanguage > e )
2013-03-22 00:35:15 +06:00
{
e . DeletedEntities . ForEach ( x => DistributedCache . Instance . RemoveLanguageCache ( x ));
}
/// <summary>
/// Fires when a langauge is saved
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
2017-02-06 17:26:06 +11:00
static void LocalizationService_SavedLanguage ( ILocalizationService sender , SaveEventArgs < ILanguage > e )
2013-03-22 00:35:15 +06:00
{
e . SavedEntities . ForEach ( x => DistributedCache . Instance . RefreshLanguageCache ( x ));
}
2016-11-24 17:37:20 +01:00
2013-03-22 01:49:34 +06:00
#endregion
2013-03-22 00:35:15 +06:00
2014-01-23 13:33:58 +11:00
#region Content / media / member Type event handlers
2013-03-21 01:04:27 +06:00
/// <summary>
/// Fires when a media type is deleted
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
2017-02-06 17:26:06 +11:00
static void ContentTypeService_DeletedMediaType ( IContentTypeService sender , DeleteEventArgs < IMediaType > e )
2013-03-21 01:04:27 +06:00
{
e . DeletedEntities . ForEach ( x => DistributedCache . Instance . RemoveMediaTypeCache ( x ));
}
/// <summary>
/// Fires when a content type is deleted
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
2017-02-06 17:26:06 +11:00
static void ContentTypeService_DeletedContentType ( IContentTypeService sender , DeleteEventArgs < IContentType > e )
2013-03-21 01:04:27 +06:00
{
e . DeletedEntities . ForEach ( contentType => DistributedCache . Instance . RemoveContentTypeCache ( contentType ));
}
2014-01-23 13:33:58 +11:00
/// <summary>
/// Fires when a member type is deleted
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
2017-02-06 17:26:06 +11:00
static void MemberTypeService_Deleted ( IMemberTypeService sender , DeleteEventArgs < IMemberType > e )
2014-01-23 13:33:58 +11:00
{
e . DeletedEntities . ForEach ( contentType => DistributedCache . Instance . RemoveMemberTypeCache ( contentType ));
}
2013-03-16 08:47:55 +06:00
/// <summary>
/// Fires when a media type is saved
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
2017-02-06 17:26:06 +11:00
static void ContentTypeService_SavedMediaType ( IContentTypeService sender , SaveEventArgs < IMediaType > e )
2013-03-16 08:47:55 +06:00
{
2013-03-21 08:38:18 +06:00
e . SavedEntities . ForEach ( x => DistributedCache . Instance . RefreshMediaTypeCache ( x ));
2013-03-16 08:47:55 +06:00
}
/// <summary>
/// Fires when a content type is saved
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
2017-02-06 17:26:06 +11:00
static void ContentTypeService_SavedContentType ( IContentTypeService sender , SaveEventArgs < IContentType > e )
2013-03-22 01:49:34 +06:00
{
2013-03-21 08:38:18 +06:00
e . SavedEntities . ForEach ( contentType => DistributedCache . Instance . RefreshContentTypeCache ( contentType ));
2014-01-23 13:33:58 +11:00
}
/// <summary>
/// Fires when a member type is saved
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
2017-02-06 17:26:06 +11:00
static void MemberTypeService_Saved ( IMemberTypeService sender , SaveEventArgs < IMemberType > e )
2014-01-23 13:33:58 +11:00
{
e . SavedEntities . ForEach ( x => DistributedCache . Instance . RefreshMemberTypeCache ( x ));
}
2016-11-24 17:37:20 +01:00
2013-03-22 01:49:34 +06:00
#endregion
2016-11-24 17:37:20 +01:00
2014-02-17 17:45:59 +11:00
#region User / permissions event handlers
2017-02-17 09:54:50 +01:00
2017-07-13 18:47:10 +10:00
static 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();
//foreach (var groupId in groupIds)
//{
// DistributedCache.Instance.RefreshUserGroupPermissionsCache(groupId);
//}
}
2014-01-28 12:13:27 +11:00
2017-02-06 17:26:06 +11:00
static void UserService_SavedUser ( IUserService sender , SaveEventArgs < IUser > e )
2014-01-28 12:13:27 +11:00
{
e . SavedEntities . ForEach ( x => DistributedCache . Instance . RefreshUserCache ( x . Id ));
}
2017-02-06 17:26:06 +11:00
static void UserService_DeletedUser ( IUserService sender , DeleteEventArgs < IUser > e )
2014-01-28 12:13:27 +11:00
{
e . DeletedEntities . ForEach ( x => DistributedCache . Instance . RemoveUserCache ( x . Id ));
}
2016-11-24 17:37:20 +01:00
2017-05-11 20:51:31 +10:00
static void UserService_SavedUserGroup ( IUserService sender , SaveEventArgs < IUserGroup > e )
2013-04-04 00:30:28 +06:00
{
2016-10-28 09:20:52 +02:00
e . SavedEntities . ForEach ( x => DistributedCache . Instance . RefreshUserGroupCache ( x . Id ));
}
2017-05-11 20:51:31 +10:00
static void UserService_DeletedUserGroup ( IUserService sender , DeleteEventArgs < IUserGroup > e )
2016-10-28 09:20:52 +02:00
{
e . DeletedEntities . ForEach ( x => DistributedCache . Instance . RemoveUserGroupCache ( x . Id ));
}
2017-07-13 11:02:34 +10:00
2013-04-04 00:30:28 +06:00
2013-03-22 01:49:34 +06:00
#endregion
2013-02-12 04:13:29 +06:00
2013-03-22 01:49:34 +06:00
#region Template event handlers
2013-03-22 02:08:55 +06:00
/// <summary>
/// Removes cache for template
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
2017-02-06 17:26:06 +11:00
static void FileService_DeletedTemplate ( IFileService sender , DeleteEventArgs < ITemplate > e )
2013-03-22 02:08:55 +06:00
{
2017-08-24 18:38:40 +10:00
foreach ( var x in e . DeletedEntities )
{
DistributedCache . Instance . RemoveTemplateCache ( x . Id );
}
2013-03-22 02:08:55 +06:00
}
/// <summary>
/// Refresh cache for template
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
2017-02-06 17:26:06 +11:00
static void FileService_SavedTemplate ( IFileService sender , SaveEventArgs < ITemplate > e )
2013-03-22 02:08:55 +06:00
{
2017-08-24 18:38:40 +10:00
foreach ( var x in e . SavedEntities )
{
DistributedCache . Instance . RefreshTemplateCache ( x . Id );
}
2013-03-22 02:08:55 +06:00
}
2016-11-24 17:37:20 +01:00
2013-03-22 01:49:34 +06:00
#endregion
2013-02-07 05:26:53 +06:00
2013-03-22 01:49:34 +06:00
#region Macro event handlers
2013-10-31 17:22:10 +11:00
2017-02-06 17:26:06 +11:00
static void MacroService_Deleted ( IMacroService sender , DeleteEventArgs < IMacro > e )
2013-10-31 17:22:10 +11:00
{
foreach ( var entity in e . DeletedEntities )
{
DistributedCache . Instance . RemoveMacroCache ( entity );
}
}
2017-02-06 17:26:06 +11:00
static void MacroService_Saved ( IMacroService sender , SaveEventArgs < IMacro > e )
2013-10-31 17:22:10 +11:00
{
foreach ( var entity in e . SavedEntities )
{
DistributedCache . Instance . RefreshMacroCache ( entity );
}
}
2016-11-24 17:37:20 +01:00
2013-03-22 01:49:34 +06:00
#endregion
2013-02-07 04:45:05 +06:00
2013-03-22 01:49:34 +06:00
#region Media event handlers
2014-04-23 20:19:36 +10:00
2017-02-06 17:26:06 +11:00
static void MediaService_EmptiedRecycleBin ( IMediaService sender , RecycleBinEventArgs e )
2013-02-06 09:53:13 +06:00
{
2014-04-23 20:19:36 +10:00
if ( e . RecycleBinEmptiedSuccessfully && e . IsMediaRecycleBin )
{
DistributedCache . Instance . RemoveMediaCachePermanently ( e . Ids . ToArray ());
}
2013-02-06 09:53:13 +06:00
}
2017-02-06 17:26:06 +11:00
static void MediaService_Trashed ( IMediaService sender , MoveEventArgs < IMedia > e )
2013-02-06 09:53:13 +06:00
{
2014-04-23 20:19:36 +10:00
DistributedCache . Instance . RemoveMediaCacheAfterRecycling ( e . MoveInfoCollection . ToArray ());
2013-02-06 09:53:13 +06:00
}
2017-02-06 17:26:06 +11:00
static void MediaService_Moved ( IMediaService sender , MoveEventArgs < IMedia > e )
2013-02-06 09:53:13 +06:00
{
2014-04-23 20:19:36 +10:00
DistributedCache . Instance . RefreshMediaCacheAfterMoving ( e . MoveInfoCollection . ToArray ());
}
2017-02-06 17:26:06 +11:00
static void MediaService_Deleted ( IMediaService sender , DeleteEventArgs < IMedia > e )
2014-04-23 20:19:36 +10:00
{
DistributedCache . Instance . RemoveMediaCachePermanently ( e . DeletedEntities . Select ( x => x . Id ). ToArray ());
2013-02-06 09:53:13 +06:00
}
2017-02-06 17:26:06 +11:00
static void MediaService_Saved ( IMediaService sender , SaveEventArgs < IMedia > e )
2013-02-06 09:53:13 +06:00
{
2013-02-12 07:35:47 +06:00
DistributedCache . Instance . RefreshMediaCache ( e . SavedEntities . ToArray ());
2016-11-24 17:37:20 +01:00
}
2013-03-22 01:49:34 +06:00
#endregion
2013-02-06 09:53:13 +06:00
2013-03-22 01:49:34 +06:00
#region Member event handlers
2013-10-18 16:23:33 +11:00
2017-02-06 17:26:06 +11:00
static void MemberService_Deleted ( IMemberService sender , DeleteEventArgs < IMember > e )
2013-10-18 16:23:33 +11:00
{
2016-11-24 17:37:20 +01:00
DistributedCache . Instance . RemoveMemberCache ( e . DeletedEntities . ToArray ());
2013-02-06 09:53:13 +06:00
}
2017-02-06 17:26:06 +11:00
static void MemberService_Saved ( IMemberService sender , SaveEventArgs < IMember > e )
2013-02-06 09:53:13 +06:00
{
2014-03-06 18:25:38 +11:00
DistributedCache . Instance . RefreshMemberCache ( e . SavedEntities . ToArray ());
2013-10-18 16:23:33 +11:00
}
2013-03-22 01:49:34 +06:00
#endregion
2014-02-12 17:14:16 +11:00
#region Member group event handlers
2014-03-06 18:25:38 +11:00
static void MemberGroupService_Deleted ( IMemberGroupService sender , DeleteEventArgs < IMemberGroup > e )
2013-10-18 16:23:33 +11:00
{
2014-02-12 17:14:16 +11:00
foreach ( var m in e . DeletedEntities . ToArray ())
2013-10-18 16:23:33 +11:00
{
2014-02-12 17:14:16 +11:00
DistributedCache . Instance . RemoveMemberGroupCache ( m . Id );
2013-10-18 16:23:33 +11:00
}
}
2014-03-06 18:25:38 +11:00
static void MemberGroupService_Saved ( IMemberGroupService sender , SaveEventArgs < IMemberGroup > e )
2013-02-06 09:53:13 +06:00
{
2014-02-12 17:14:16 +11:00
foreach ( var m in e . SavedEntities . ToArray ())
{
DistributedCache . Instance . RemoveMemberGroupCache ( m . Id );
}
2016-11-09 13:05:23 +01:00
}
#endregion
#region Relation type event handlers
2017-02-06 17:26:06 +11:00
static void RelationService_SavedRelationType ( IRelationService sender , SaveEventArgs < IRelationType > args )
2016-11-09 13:05:23 +01:00
{
var dc = DistributedCache . Instance ;
foreach ( var e in args . SavedEntities )
dc . RefreshRelationTypeCache ( e . Id );
}
2017-02-06 17:26:06 +11:00
static void RelationService_DeletedRelationType ( IRelationService sender , DeleteEventArgs < IRelationType > args )
2016-11-09 13:05:23 +01:00
{
var dc = DistributedCache . Instance ;
foreach ( var e in args . DeletedEntities )
dc . RemoveRelationTypeCache ( e . Id );
}
2013-03-22 01:49:34 +06:00
#endregion
2017-02-06 17:26:06 +11:00
/// <summary>
/// This will inspect the event metadata and execute it's affiliated handler if one is found
/// </summary>
/// <param name="events"></param>
internal static void HandleEvents ( IEnumerable < IEventDefinition > events )
2017-05-04 18:29:43 +10:00
{
//TODO: We should remove this in v8, this is a backwards compat hack and is needed because when we are using Deploy, the events will be raised on a background
//thread which means that cache refreshers will also execute on a background thread and in many cases developers may be using UmbracoContext.Current in their
2017-05-01 21:10:22 +10:00
//cache refresher handlers, so before we execute all of the events, we'll ensure a context
UmbracoContext tempContext = null ;
if ( UmbracoContext . Current == null )
2017-02-06 17:26:06 +11:00
{
2017-05-01 21:10:22 +10:00
var httpContext = new HttpContextWrapper ( HttpContext . Current ?? new HttpContext ( new SimpleWorkerRequest ( "temp.aspx" , "" , new StringWriter ())));
tempContext = UmbracoContext . EnsureContext (
httpContext ,
ApplicationContext . Current ,
new WebSecurity ( httpContext , ApplicationContext . Current ),
UmbracoConfig . For . UmbracoSettings (),
UrlProviderResolver . Current . Providers ,
true );
2017-02-06 17:26:06 +11:00
}
2017-05-01 21:10:22 +10:00
try
{
foreach ( var e in events )
{
var handler = FindHandler ( e );
if ( handler == null ) continue ;
handler . Invoke ( null , new [] { e . Sender , e . Args });
}
}
finally
{
2017-05-04 18:29:43 +10:00
if ( tempContext != null )
2017-07-13 13:11:46 +02:00
tempContext . Dispose (); // nulls the ThreadStatic context
2017-05-01 21:10:22 +10:00
}
2017-02-06 17:26:06 +11:00
}
/// <summary>
/// Used to cache all candidate handlers
/// </summary>
private static readonly Lazy < MethodInfo []> CandidateHandlers = new Lazy < MethodInfo []>(() =>
{
2017-02-17 09:54:50 +01:00
var underscore = new [] { '_' };
2017-02-06 17:26:06 +11:00
2017-02-17 09:54:50 +01:00
return typeof ( CacheRefresherEventHandler )
. GetMethods ( BindingFlags . Static | BindingFlags . Public | BindingFlags . NonPublic )
. Select ( x =>
{
if ( x . Name . Contains ( "_" ) == false ) return null ;
2017-02-06 17:26:06 +11:00
2017-02-17 09:54:50 +01:00
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 ();
2017-02-06 17:26:06 +11:00
});
/// <summary>
/// Used to cache all found event handlers
/// </summary>
private static readonly ConcurrentDictionary < IEventDefinition , MethodInfo > FoundHandlers = new ConcurrentDictionary < IEventDefinition , MethodInfo >();
internal static MethodInfo FindHandler ( IEventDefinition eventDefinition )
{
2017-02-17 09:54:50 +01:00
var name = eventDefinition . Sender . GetType (). Name + "_" + eventDefinition . EventName ;
2017-02-06 17:26:06 +11:00
2017-02-17 09:54:50 +01:00
return FoundHandlers . GetOrAdd ( eventDefinition , _ => CandidateHandlers . Value . FirstOrDefault ( x => x . Name == name ));
2017-02-06 17:26:06 +11:00
}
2013-02-06 09:53:13 +06:00
}
}