Skip to content

Commit

Permalink
Merge pull request #8815 from umbraco/v8/bugfix/events-unsubscribe
Browse files Browse the repository at this point in the history
Ensure event handlers are unsubscribed  in Core Components

(cherry picked from commit e7f98a5)
  • Loading branch information
Warren Buckley authored and nul800sebastiaan committed Sep 21, 2020
1 parent ecff240 commit 3950f32
Show file tree
Hide file tree
Showing 11 changed files with 202 additions and 85 deletions.
14 changes: 13 additions & 1 deletion src/Umbraco.Core/Compose/AuditEventsComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,19 @@ public void Initialize()
}

public void Terminate()
{ }
{
UserService.SavedUserGroup -= OnSavedUserGroupWithUsers;

UserService.SavedUser -= OnSavedUser;
UserService.DeletedUser -= OnDeletedUser;
UserService.UserGroupPermissionsAssigned -= UserGroupPermissionAssigned;

MemberService.Saved -= OnSavedMember;
MemberService.Deleted -= OnDeletedMember;
MemberService.AssignedRoles -= OnAssignedRoles;
MemberService.RemovedRoles -= OnRemovedRoles;
MemberService.Exported -= OnMemberExported;
}

internal static IUser UnknownUser => new User { Id = Constants.Security.UnknownUserId, Name = Constants.Security.UnknownUserName, Email = "" };

Expand Down
4 changes: 3 additions & 1 deletion src/Umbraco.Core/Compose/RelateOnCopyComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ public void Initialize()
}

public void Terminate()
{ }
{
ContentService.Copied -= ContentServiceCopied;
}

private static void ContentServiceCopied(IContentService sender, Events.CopyEventArgs<IContent> e)
{
Expand Down
7 changes: 6 additions & 1 deletion src/Umbraco.Core/Compose/RelateOnTrashComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ public void Initialize()
}

public void Terminate()
{ }
{
ContentService.Moved -= ContentService_Moved;
ContentService.Trashed -= ContentService_Trashed;
MediaService.Moved -= MediaService_Moved;
MediaService.Trashed -= MediaService_Trashed;
}

private static void ContentService_Moved(IContentService sender, MoveEventArgs<IContent> e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,32 +50,38 @@ public void Initialize()
}

public void Terminate()
{ }
{
ServerVariablesParser.Parsing -= ServerVariablesParser_Parsing;
ContentModelBinder.ModelBindingException -= ContentModelBinder_ModelBindingException;
FileService.SavingTemplate -= FileService_SavingTemplate;
}

private void InstallServerVars()
{
// register our url - for the backoffice api
ServerVariablesParser.Parsing += (sender, serverVars) =>
{
if (!serverVars.ContainsKey("umbracoUrls"))
throw new ArgumentException("Missing umbracoUrls.");
var umbracoUrlsObject = serverVars["umbracoUrls"];
if (umbracoUrlsObject == null)
throw new ArgumentException("Null umbracoUrls");
if (!(umbracoUrlsObject is Dictionary<string, object> umbracoUrls))
throw new ArgumentException("Invalid umbracoUrls");

if (!serverVars.ContainsKey("umbracoPlugins"))
throw new ArgumentException("Missing umbracoPlugins.");
if (!(serverVars["umbracoPlugins"] is Dictionary<string, object> umbracoPlugins))
throw new ArgumentException("Invalid umbracoPlugins");

if (HttpContext.Current == null) throw new InvalidOperationException("HttpContext is null");
var urlHelper = new UrlHelper(new RequestContext(new HttpContextWrapper(HttpContext.Current), new RouteData()));

umbracoUrls["modelsBuilderBaseUrl"] = urlHelper.GetUmbracoApiServiceBaseUrl<ModelsBuilderDashboardController>(controller => controller.BuildModels());
umbracoPlugins["modelsBuilder"] = GetModelsBuilderSettings();
};
ServerVariablesParser.Parsing += ServerVariablesParser_Parsing;
}

private void ServerVariablesParser_Parsing(object sender, Dictionary<string, object> serverVars)
{
if (!serverVars.ContainsKey("umbracoUrls"))
throw new ArgumentException("Missing umbracoUrls.");
var umbracoUrlsObject = serverVars["umbracoUrls"];
if (umbracoUrlsObject == null)
throw new ArgumentException("Null umbracoUrls");
if (!(umbracoUrlsObject is Dictionary<string, object> umbracoUrls))
throw new ArgumentException("Invalid umbracoUrls");

if (!serverVars.ContainsKey("umbracoPlugins"))
throw new ArgumentException("Missing umbracoPlugins.");
if (!(serverVars["umbracoPlugins"] is Dictionary<string, object> umbracoPlugins))
throw new ArgumentException("Invalid umbracoPlugins");

if (HttpContext.Current == null) throw new InvalidOperationException("HttpContext is null");
var urlHelper = new UrlHelper(new RequestContext(new HttpContextWrapper(HttpContext.Current), new RouteData()));

umbracoUrls["modelsBuilderBaseUrl"] = urlHelper.GetUmbracoApiServiceBaseUrl<ModelsBuilderDashboardController>(controller => controller.BuildModels());
umbracoPlugins["modelsBuilder"] = GetModelsBuilderSettings();
}

private Dictionary<string, object> GetModelsBuilderSettings()
Expand Down
14 changes: 13 additions & 1 deletion src/Umbraco.Web/Compose/BackOfficeUserAuditEventsComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,19 @@ public void Initialize()
}

public void Terminate()
{ }
{
//BackOfficeUserManager.AccountLocked -= ;
//BackOfficeUserManager.AccountUnlocked -= ;
BackOfficeUserManager.ForgotPasswordRequested -= OnForgotPasswordRequest;
BackOfficeUserManager.ForgotPasswordChangedSuccess -= OnForgotPasswordChange;
BackOfficeUserManager.LoginFailed -= OnLoginFailed;
//BackOfficeUserManager.LoginRequiresVerification -= ;
BackOfficeUserManager.LoginSuccess -= OnLoginSuccess;
BackOfficeUserManager.LogoutSuccess -= OnLogoutSuccess;
BackOfficeUserManager.PasswordChanged -= OnPasswordChanged;
BackOfficeUserManager.PasswordReset -= OnPasswordReset;
//BackOfficeUserManager.ResetAccessFailedCount -= ;
}

private IUser GetPerformingUser(int userId)
{
Expand Down
110 changes: 73 additions & 37 deletions src/Umbraco.Web/Compose/NotificationsComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,42 +32,78 @@ public NotificationsComponent(Notifier notifier, ActionCollection actions, ICont
public void Initialize()
{
//Send notifications for the send to publish action
ContentService.SentToPublish += (sender, args) => _notifier.Notify(_actions.GetAction<ActionToPublish>(), args.Entity);

ContentService.SentToPublish += ContentService_SentToPublish;
//Send notifications for the published action
ContentService.Published += (sender, args) => _notifier.Notify(_actions.GetAction<ActionPublish>(), args.PublishedEntities.ToArray());

ContentService.Published += ContentService_Published;
//Send notifications for the saved action
ContentService.Sorted += (sender, args) => ContentServiceSorted(_notifier, sender, args, _actions);

ContentService.Sorted += ContentService_Sorted;
//Send notifications for the update and created actions
ContentService.Saved += (sender, args) => ContentServiceSaved(_notifier, sender, args, _actions);

ContentService.Saved += ContentService_Saved;
//Send notifications for the unpublish action
ContentService.Unpublished += (sender, args) => _notifier.Notify(_actions.GetAction<ActionUnpublish>(), args.PublishedEntities.ToArray());

ContentService.Unpublished += ContentService_Unpublished;
//Send notifications for the move/move to recycle bin and restore actions
ContentService.Moved += (sender, args) => ContentServiceMoved(_notifier, sender, args, _actions);

ContentService.Moved += ContentService_Moved;
//Send notifications for the delete action when content is moved to the recycle bin
ContentService.Trashed += (sender, args) => _notifier.Notify(_actions.GetAction<ActionDelete>(), args.MoveInfoCollection.Select(m => m.Entity).ToArray());

ContentService.Trashed += ContentService_Trashed;
//Send notifications for the copy action
ContentService.Copied += (sender, args) => _notifier.Notify(_actions.GetAction<ActionCopy>(), args.Original);

ContentService.Copied += ContentService_Copied;
//Send notifications for the rollback action
ContentService.RolledBack += (sender, args) => _notifier.Notify(_actions.GetAction<ActionRollback>(), args.Entity);

ContentService.RolledBack += ContentService_RolledBack;
//Send notifications for the public access changed action
PublicAccessService.Saved += (sender, args) => PublicAccessServiceSaved(_notifier, sender, args, _contentService, _actions);
UserService.UserGroupPermissionsAssigned += (sender, args) => UserServiceUserGroupPermissionsAssigned(_notifier, sender, args, _contentService, _actions);
PublicAccessService.Saved += PublicAccessService_Saved;

UserService.UserGroupPermissionsAssigned += UserService_UserGroupPermissionsAssigned;
}

public void Terminate()
{ }
{
ContentService.SentToPublish -= ContentService_SentToPublish;
ContentService.Published -= ContentService_Published;
ContentService.Sorted -= ContentService_Sorted;
ContentService.Saved -= ContentService_Saved;
ContentService.Unpublished -= ContentService_Unpublished;
ContentService.Moved -= ContentService_Moved;
ContentService.Trashed -= ContentService_Trashed;
ContentService.Copied -= ContentService_Copied;
ContentService.RolledBack -= ContentService_RolledBack;
PublicAccessService.Saved -= PublicAccessService_Saved;
UserService.UserGroupPermissionsAssigned -= UserService_UserGroupPermissionsAssigned;
}

private void UserService_UserGroupPermissionsAssigned(IUserService sender, Core.Events.SaveEventArgs<EntityPermission> args)
=> UserServiceUserGroupPermissionsAssigned(args, _contentService);

private void PublicAccessService_Saved(IPublicAccessService sender, Core.Events.SaveEventArgs<PublicAccessEntry> args)
=> PublicAccessServiceSaved(args, _contentService);

private void ContentServiceSorted(Notifier notifier, IContentService sender, Core.Events.SaveEventArgs<IContent> args, ActionCollection actions)
private void ContentService_RolledBack(IContentService sender, Core.Events.RollbackEventArgs<IContent> args)
=> _notifier.Notify(_actions.GetAction<ActionRollback>(), args.Entity);

private void ContentService_Copied(IContentService sender, Core.Events.CopyEventArgs<IContent> args)
=> _notifier.Notify(_actions.GetAction<ActionCopy>(), args.Original);

private void ContentService_Trashed(IContentService sender, Core.Events.MoveEventArgs<IContent> args)
=> _notifier.Notify(_actions.GetAction<ActionDelete>(), args.MoveInfoCollection.Select(m => m.Entity).ToArray());

private void ContentService_Moved(IContentService sender, Core.Events.MoveEventArgs<IContent> args)
=> ContentServiceMoved(args);

private void ContentService_Unpublished(IContentService sender, Core.Events.PublishEventArgs<IContent> args)
=> _notifier.Notify(_actions.GetAction<ActionUnpublish>(), args.PublishedEntities.ToArray());

private void ContentService_Saved(IContentService sender, Core.Events.ContentSavedEventArgs args)
=> ContentServiceSaved(args);

private void ContentService_Sorted(IContentService sender, Core.Events.SaveEventArgs<IContent> args)
=> ContentServiceSorted(sender, args);

private void ContentService_Published(IContentService sender, Core.Events.ContentPublishedEventArgs args)
=> _notifier.Notify(_actions.GetAction<ActionPublish>(), args.PublishedEntities.ToArray());

private void ContentService_SentToPublish(IContentService sender, Core.Events.SendToPublishEventArgs<IContent> args)
=> _notifier.Notify(_actions.GetAction<ActionToPublish>(), args.Entity);

private void ContentServiceSorted(IContentService sender, Core.Events.SaveEventArgs<IContent> args)
{
var parentId = args.SavedEntities.Select(x => x.ParentId).Distinct().ToList();
if (parentId.Count != 1) return; // this shouldn't happen, for sorting all entities will have the same parent id
Expand All @@ -79,10 +115,10 @@ private void ContentServiceSorted(Notifier notifier, IContentService sender, Cor
var parent = sender.GetById(parentId[0]);
if (parent == null) return; // this shouldn't happen

notifier.Notify(actions.GetAction<ActionSort>(), new[] { parent });
_notifier.Notify(_actions.GetAction<ActionSort>(), new[] { parent });
}

private void ContentServiceSaved(Notifier notifier, IContentService sender, Core.Events.SaveEventArgs<IContent> args, ActionCollection actions)
private void ContentServiceSaved(Core.Events.SaveEventArgs<IContent> args)
{
var newEntities = new List<IContent>();
var updatedEntities = new List<IContent>();
Expand All @@ -102,21 +138,21 @@ private void ContentServiceSaved(Notifier notifier, IContentService sender, Core
updatedEntities.Add(entity);
}
}
notifier.Notify(actions.GetAction<ActionNew>(), newEntities.ToArray());
notifier.Notify(actions.GetAction<ActionUpdate>(), updatedEntities.ToArray());
_notifier.Notify(_actions.GetAction<ActionNew>(), newEntities.ToArray());
_notifier.Notify(_actions.GetAction<ActionUpdate>(), updatedEntities.ToArray());
}

private void UserServiceUserGroupPermissionsAssigned(Notifier notifier, IUserService sender, Core.Events.SaveEventArgs<EntityPermission> args, IContentService contentService, ActionCollection actions)
private void UserServiceUserGroupPermissionsAssigned(Core.Events.SaveEventArgs<EntityPermission> args, IContentService contentService)
{
var entities = contentService.GetByIds(args.SavedEntities.Select(e => e.EntityId)).ToArray();
if(entities.Any() == false)
if (entities.Any() == false)
{
return;
}
notifier.Notify(actions.GetAction<ActionRights>(), entities);
_notifier.Notify(_actions.GetAction<ActionRights>(), entities);
}
private void ContentServiceMoved(Notifier notifier, IContentService sender, Core.Events.MoveEventArgs<IContent> args, ActionCollection actions)

private void ContentServiceMoved(Core.Events.MoveEventArgs<IContent> args)
{
// notify about the move for all moved items
_notifier.Notify(_actions.GetAction<ActionMove>(), args.MoveInfoCollection.Select(m => m.Entity).ToArray());
Expand All @@ -126,22 +162,22 @@ private void ContentServiceMoved(Notifier notifier, IContentService sender, Core
.Where(m => m.OriginalPath.Contains(Constants.System.RecycleBinContentString))
.Select(m => m.Entity)
.ToArray();
if(restoredEntities.Any())
if (restoredEntities.Any())
{
_notifier.Notify(_actions.GetAction<ActionRestore>(), restoredEntities);
}
}

private void PublicAccessServiceSaved(Notifier notifier, IPublicAccessService sender, Core.Events.SaveEventArgs<PublicAccessEntry> args, IContentService contentService, ActionCollection actions)
private void PublicAccessServiceSaved(Core.Events.SaveEventArgs<PublicAccessEntry> args, IContentService contentService)
{
var entities = contentService.GetByIds(args.SavedEntities.Select(e => e.ProtectedNodeId)).ToArray();
if(entities.Any() == false)
if (entities.Any() == false)
{
return;
}
notifier.Notify(actions.GetAction<ActionProtect>(), entities);
_notifier.Notify(_actions.GetAction<ActionProtect>(), entities);
}

/// <summary>
/// This class is used to send the notifications
/// </summary>
Expand Down
4 changes: 3 additions & 1 deletion src/Umbraco.Web/Compose/PublicAccessComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ public void Initialize()
}

public void Terminate()
{ }
{
MemberGroupService.Saved -= MemberGroupService_Saved;
}

static void MemberGroupService_Saved(IMemberGroupService sender, Core.Events.SaveEventArgs<Core.Models.IMemberGroup> e)
{
Expand Down
16 changes: 13 additions & 3 deletions src/Umbraco.Web/Logging/WebProfilerComponent.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Web;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
Expand All @@ -9,6 +10,7 @@ internal sealed class WebProfilerComponent : IComponent
{
private readonly WebProfiler _profiler;
private readonly bool _profile;
private readonly List<Action> _terminate = new List<Action>();

public WebProfilerComponent(IProfiler profiler, ILogger logger)
{
Expand All @@ -35,15 +37,23 @@ public void Initialize()
}

public void Terminate()
{ }
{
UmbracoApplicationBase.ApplicationInit -= InitializeApplication;
foreach (var t in _terminate) t();
}

private void InitializeApplication(object sender, EventArgs args)
{
if (!(sender is HttpApplication app)) return;

// for *each* application (this will run more than once)
app.BeginRequest += (s, a) => _profiler.UmbracoApplicationBeginRequest(s, a);
app.EndRequest += (s, a) => _profiler.UmbracoApplicationEndRequest(s, a);
void beginRequest(object s, EventArgs a) => _profiler.UmbracoApplicationBeginRequest(s, a);
app.BeginRequest += beginRequest;
_terminate.Add(() => app.BeginRequest -= beginRequest);

void endRequest(object s, EventArgs a) => _profiler.UmbracoApplicationEndRequest(s, a);
app.EndRequest += endRequest;
_terminate.Add(() => app.EndRequest -= endRequest);
}
}
}
Loading

0 comments on commit 3950f32

Please sign in to comment.