Resvolution - ActionResolver

This commit is contained in:
Stephan
2016-07-29 15:48:32 +02:00
parent d8d736edda
commit bbd632f644
18 changed files with 316 additions and 369 deletions

View File

@@ -68,44 +68,6 @@ namespace Umbraco.Core.ObjectResolution
// about using it for anything else. Also, while the backdoor is open, the resolution system is locked so nothing
// can work properly => deadlocks. Therefore, open the backdoor, do resolution changes EXCLUSIVELY, and close the door!
/// <summary>
/// Returns a disposable object that reprents dirty access to temporarily unfrozen resolution configuration.
/// </summary>
/// <remarks>
/// <para>Should not be used.</para>
/// <para>Should be used in a <c>using(Resolution.DirtyBackdoorToConfiguration) { ... }</c> mode.</para>
/// <para>Because we just lift the frozen state, and we don't actually re-freeze, the <c>Frozen</c> event does not trigger.</para>
/// </remarks>
internal static IDisposable DirtyBackdoorToConfiguration
{
get { return new DirtyBackdoor(); }
}
// keep the class here because it needs write-access to Resolution.IsFrozen
private class DirtyBackdoor : IDisposable
{
private readonly IDisposable _lock;
private readonly bool _frozen;
public DirtyBackdoor()
{
LogHelper.Debug(typeof(DirtyBackdoor), "Creating back door for resolution");
_lock = new WriteLock(ConfigurationLock);
_frozen = _isFrozen;
_isFrozen = false;
}
public void Dispose()
{
LogHelper.Debug(typeof(DirtyBackdoor), "Disposing back door for resolution");
_isFrozen = _frozen;
_lock.Dispose();
}
}
/// <summary>
/// Freezes resolution.
/// </summary>

View File

@@ -1,184 +1,177 @@
using System.Linq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.ObjectResolution;
using Umbraco.Web.UI.Pages;
using Umbraco.Web;
using Umbraco.Web._Legacy.Actions;
namespace Umbraco.Tests.Resolvers
{
[TestFixture]
public class ActionsResolverTests : ResolverBaseTest
{
[TearDown]
public void TearDown()
{
ActionsResolver.Reset();
}
// NOTE
// ManyResolverTests ensure that we'll get our actions back and ActionsResolver works,
// so all we're testing here is that plugin manager _does_ find our actions
// which should be ensured by PlugingManagerTests anyway, so this is useless?
// maybe not as it seems to handle the "instance" thing... so we test that we respect the singleton?
[Test]
public void FindAllActions()
{
ActionsResolver.Current = new ActionsResolver(
new ActivatorServiceProvider(), ProfilingLogger.Logger,
() => PluginManager.ResolveActions());
Resolution.Freeze();
var actions = ActionsResolver.Current.Actions;
Assert.AreEqual(2, actions.Count());
// order is unspecified, but both must be there
bool hasAction1 = actions.ElementAt(0) is SingletonAction || actions.ElementAt(1) is SingletonAction;
bool hasAction2 = actions.ElementAt(0) is NonSingletonAction || actions.ElementAt(1) is NonSingletonAction;
Assert.IsTrue(hasAction1);
Assert.IsTrue(hasAction2);
SingletonAction action = (SingletonAction)(actions.ElementAt(0) is SingletonAction ? actions.ElementAt(0) : actions.ElementAt(1));
// ensure we respect the singleton
Assert.AreSame(SingletonAction.Instance, action);
}
#region Classes for tests
public class SingletonAction : IAction
{
//create singleton
private static readonly SingletonAction instance = new SingletonAction();
public static SingletonAction Instance
{
get { return instance; }
}
#region IAction Members
public char Letter
{
get
{
return 'I';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionAssignDomain()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "assignDomain";
}
}
public string Icon
{
get
{
return ".sprDomain";
}
}
public bool ShowInNotifier
{
get
{
return false;
}
}
public bool CanBePermissionAssigned
{
get
{
return true;
}
}
#endregion
}
public class NonSingletonAction : IAction
{
#region IAction Members
public char Letter
{
get
{
return 'Q';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionAssignDomain()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "asfasdf";
}
}
public string Icon
{
get
{
return ".sprDomain";
}
}
public bool ShowInNotifier
{
get
{
return false;
}
}
public bool CanBePermissionAssigned
{
get
{
return true;
}
}
#endregion
}
#endregion
}
using System.Linq;
using LightInject;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.DependencyInjection;
using Umbraco.Core.ObjectResolution;
using Umbraco.Web.UI.Pages;
using Umbraco.Web;
using Umbraco.Web._Legacy.Actions;
namespace Umbraco.Tests.Resolvers
{
[TestFixture]
public class ActionCollectionTests : ResolverBaseTest
{
// NOTE
// ManyResolverTests ensure that we'll get our actions back and ActionsResolver works,
// so all we're testing here is that plugin manager _does_ find our actions
// which should be ensured by PlugingManagerTests anyway, so this is useless?
// maybe not as it seems to handle the "instance" thing... so we test that we respect the singleton?
[Test]
public void FindAllActions()
{
var collectionBuilder = new ActionCollectionBuilder();
collectionBuilder.SetProducer(() => PluginManager.ResolveActions());
var actions = collectionBuilder.CreateCollection();
Assert.AreEqual(2, actions.Count());
// order is unspecified, but both must be there
var hasAction1 = actions.ElementAt(0) is SingletonAction || actions.ElementAt(1) is SingletonAction;
var hasAction2 = actions.ElementAt(0) is NonSingletonAction || actions.ElementAt(1) is NonSingletonAction;
Assert.IsTrue(hasAction1);
Assert.IsTrue(hasAction2);
var action = (SingletonAction)(actions.ElementAt(0) is SingletonAction ? actions.ElementAt(0) : actions.ElementAt(1));
// ensure we respect the singleton
Assert.AreSame(SingletonAction.Instance, action);
}
#region Classes for tests
public class SingletonAction : IAction
{
//create singleton
private static readonly SingletonAction instance = new SingletonAction();
public static SingletonAction Instance
{
get { return instance; }
}
#region IAction Members
public char Letter
{
get
{
return 'I';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionAssignDomain()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "assignDomain";
}
}
public string Icon
{
get
{
return ".sprDomain";
}
}
public bool ShowInNotifier
{
get
{
return false;
}
}
public bool CanBePermissionAssigned
{
get
{
return true;
}
}
#endregion
}
public class NonSingletonAction : IAction
{
#region IAction Members
public char Letter
{
get
{
return 'Q';
}
}
public string JsFunctionName
{
get
{
return string.Format("{0}.actionAssignDomain()", ClientTools.Scripts.GetAppActions);
}
}
public string JsSource
{
get
{
return null;
}
}
public string Alias
{
get
{
return "asfasdf";
}
}
public string Icon
{
get
{
return ".sprDomain";
}
}
public bool ShowInNotifier
{
get
{
return false;
}
}
public bool CanBePermissionAssigned
{
get
{
return true;
}
}
#endregion
}
#endregion
}
}

View File

@@ -17,12 +17,6 @@ namespace Umbraco.Tests.Resolvers
[TestFixture]
public class XsltExtensionsResolverTests : ResolverBaseTest
{
[TearDown]
public void TearDown()
{
ActionsResolver.Reset();
}
// NOTE
// ManyResolverTests ensure that we'll get our actions back and ActionsResolver works,
// so all we're testing here is that plugin manager _does_ find our actions

View File

@@ -479,7 +479,7 @@
<Compile Include="Persistence\Repositories\StylesheetRepositoryTest.cs" />
<Compile Include="PublishedContent\PublishedContentMoreTests.cs" />
<Compile Include="Publishing\PublishingStrategyTests.cs" />
<Compile Include="Resolvers\ActionsResolverTests.cs" />
<Compile Include="Resolvers\ActionCollectionTests.cs" />
<Compile Include="Logging\RingBufferTest.cs" />
<Compile Include="TestHelpers\BaseUmbracoConfigurationTest.cs" />
<Compile Include="TestHelpers\DatabaseTestBehaviorAttribute.cs" />

View File

@@ -6,6 +6,7 @@ using Umbraco.Core.Strings;
using Umbraco.Web.HealthCheck;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Routing;
using Umbraco.Web._Legacy.Actions;
using CoreCurrent = Umbraco.Core.DependencyInjection.Current;
namespace Umbraco.Web
@@ -118,6 +119,12 @@ namespace Umbraco.Web
public static HealthCheckCollectionBuilder HealthCheckCollectionBuilder
=> Container.GetInstance<HealthCheckCollectionBuilder>();
public static ActionCollectionBuilder ActionCollectionBuilder
=> Container.GetInstance<ActionCollectionBuilder>();
public static ActionCollection Actions
=> Container.GetInstance<ActionCollection>();
#endregion
#region Core Getters

View File

@@ -122,7 +122,7 @@ namespace Umbraco.Web.Models.Trees
internal MenuItem CreateMenuItem<T>(string name, bool hasSeparator = false, IDictionary<string, object> additionalData = null)
where T : IAction
{
var item = ActionsResolver.Current.GetAction<T>();
var item = Current.Actions.GetAction<T>();
if (item != null)
{
var menuItem = new MenuItem(item, name)

View File

@@ -18,8 +18,8 @@ namespace Umbraco.Web.Trees
//We will not allow the tree to render unless the user has access to any of the sections that the tree gets rendered
// this is not ideal but until we change permissions to be tree based (not section) there's not much else we can do here.
[UmbracoApplicationAuthorize(
Constants.Applications.Content,
Constants.Applications.Media,
Constants.Applications.Content,
Constants.Applications.Media,
Constants.Applications.Users,
Constants.Applications.Settings,
Constants.Applications.Developer,
@@ -29,10 +29,10 @@ namespace Umbraco.Web.Trees
[CoreTree]
public class ContentTreeController : ContentTreeControllerBase
{
protected override TreeNode CreateRootNode(FormDataCollection queryStrings)
{
var node = base.CreateRootNode(queryStrings);
var node = base.CreateRootNode(queryStrings);
//if the user's start node is not default, then ensure the root doesn't have a menu
if (Security.CurrentUser.StartContentId != Constants.System.Root)
{
@@ -56,7 +56,7 @@ namespace Umbraco.Web.Trees
{
get { return Security.CurrentUser.StartContentId; }
}
/// <summary>
/// Creates a tree node for a content item based on an UmbracoEntity
/// </summary>
@@ -90,7 +90,7 @@ namespace Umbraco.Web.Trees
node.AdditionalData.Add("isContainer", true);
node.SetContainerStyle();
}
if (entity.IsPublished == false)
node.SetNotPublishedStyle();
@@ -142,7 +142,7 @@ namespace Umbraco.Web.Trees
// add default actions for *all* users
menu.Items.Add<ActionRePublish>(Services.TextService.Localize("actions", ActionRePublish.Instance.Alias)).ConvertLegacyMenuItem(null, "content", "content");
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
return menu;
}
@@ -161,7 +161,7 @@ namespace Umbraco.Web.Trees
var nodeMenu = GetAllNodeMenuItems(item);
var allowedMenuItems = GetAllowedUserMenuItemsForNode(item);
FilterUserAllowedMenuItems(nodeMenu, allowedMenuItems);
//if the media item is in the recycle bin, don't have a default menu, just show the regular menu
@@ -173,9 +173,9 @@ namespace Umbraco.Web.Trees
else
{
//set the default to create
nodeMenu.DefaultMenuAlias = ActionNew.Instance.Alias;
nodeMenu.DefaultMenuAlias = ActionNew.Instance.Alias;
}
return nodeMenu;
}
@@ -209,31 +209,45 @@ namespace Umbraco.Web.Trees
protected MenuItemCollection GetAllNodeMenuItems(IUmbracoEntity item)
{
var menu = new MenuItemCollection();
menu.Items.Add<ActionNew>(Services.TextService.Localize("actions", ActionNew.Instance.Alias));
menu.Items.Add<ActionDelete>(Services.TextService.Localize("actions", ActionDelete.Instance.Alias));
AddActionNode<ActionNew>(item, menu);
AddActionNode<ActionDelete>(item, menu);
//need to ensure some of these are converted to the legacy system - until we upgrade them all to be angularized.
menu.Items.Add<ActionMove>(Services.TextService.Localize("actions", ActionMove.Instance.Alias), true);
menu.Items.Add<ActionCopy>(Services.TextService.Localize("actions", ActionCopy.Instance.Alias));
menu.Items.Add<ActionChangeDocType>(Services.TextService.Localize("actions", ActionChangeDocType.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content");
AddActionNode<ActionMove>(item, menu, true);
AddActionNode<ActionCopy>(item, menu);
AddActionNode<ActionChangeDocType>(item, menu, convert: true);
menu.Items.Add<ActionSort>(Services.TextService.Localize("actions", ActionSort.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content");
AddActionNode<ActionSort>(item, menu, true, true);
menu.Items.Add<ActionRollback>(Services.TextService.Localize("actions", ActionRollback.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content");
menu.Items.Add<ActionAudit>(Services.TextService.Localize("actions", ActionAudit.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content");
menu.Items.Add<ActionPublish>(Services.TextService.Localize("actions", ActionPublish.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content");
menu.Items.Add<ActionToPublish>(Services.TextService.Localize("actions", ActionToPublish.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content");
menu.Items.Add<ActionAssignDomain>(Services.TextService.Localize("actions", ActionAssignDomain.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content");
menu.Items.Add<ActionRights>(Services.TextService.Localize("actions", ActionRights.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content");
menu.Items.Add<ActionProtect>(Services.TextService.Localize("actions", ActionProtect.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content");
menu.Items.Add<ActionNotify>(Services.TextService.Localize("actions", ActionNotify.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content");
menu.Items.Add<ActionSendToTranslate>(Services.TextService.Localize("actions", ActionSendToTranslate.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content");
AddActionNode<ActionRollback>(item, menu, convert: true);
AddActionNode<ActionAudit>(item, menu, convert: true);
AddActionNode<ActionPublish>(item, menu, true, true);
AddActionNode<ActionToPublish>(item, menu, convert: true);
AddActionNode<ActionAssignDomain>(item, menu, convert: true);
AddActionNode<ActionRights>(item, menu, convert: true);
AddActionNode<ActionProtect>(item, menu, true, true);
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
AddActionNode<ActionNotify>(item, menu, true, true);
AddActionNode<ActionSendToTranslate>(item, menu, convert: true);
AddActionNode<RefreshNode, ActionRefresh>(item, menu, true);
return menu;
}
private void AddActionNode<TAction>(IUmbracoEntity item, MenuItemCollection menu, bool hasSeparator = false, bool convert = false)
where TAction : IAction
{
var menuItem = menu.Items.Add<TAction>(Services.TextService.Localize("actions", Current.Actions.GetAction<TAction>().Alias), hasSeparator);
if (convert) menuItem.ConvertLegacyMenuItem(item, "content", "content");
}
private void AddActionNode<TItem, TAction>(IUmbracoEntity item, MenuItemCollection menu, bool hasSeparator = false, bool convert = false)
where TItem : MenuItem, new()
where TAction : IAction
{
var menuItem = menu.Items.Add<TItem, TAction>(Services.TextService.Localize("actions", Current.Actions.GetAction<TAction>().Alias), hasSeparator);
if (convert) menuItem.ConvertLegacyMenuItem(item, "content", "content");
}
}
}

View File

@@ -47,7 +47,7 @@ namespace Umbraco.Web.Trees
public static string GetLegacyIActionJavascript()
{
var js = new StringBuilder();
foreach (var a in ActionsResolver.Current.Actions.ToList())
foreach (var a in Current.Actions)
{
// NH: Added a try/catch block to this as an error in a 3rd party action can crash the whole menu initialization
try

View File

@@ -476,9 +476,8 @@ namespace Umbraco.Web
}));
}
ActionsResolver.Current = new ActionsResolver(
ServiceProvider, ProfilingLogger.Logger,
() => PluginManager.ResolveActions());
ActionCollectionBuilder.Register(Container)
.SetProducer(() => PluginManager.ResolveActions());
SurfaceControllerResolver.Current = new SurfaceControllerResolver(
ServiceProvider, ProfilingLogger.Logger,

View File

@@ -19,8 +19,8 @@ namespace Umbraco.Web._Legacy.Actions
///
/// The Action class itself has responsibility for registering actions and actionhandlers,
/// and contains methods which will be invoked whenever a change is made to ex. a document, media or member
///
/// An action/actionhandler will automatically be registered, using reflection
///
/// An action/actionhandler will automatically be registered, using reflection
/// which is enabling thirdparty developers to extend the core functionality of
/// umbraco without changing the codebase.
/// </summary>
@@ -47,20 +47,8 @@ namespace Umbraco.Web._Legacy.Actions
{
lock (Lock)
{
// NOTE use the DirtyBackdoor to change the resolution configuration EXCLUSIVELY
// ie do NOT do ANYTHING else while holding the backdoor, because while it is open
// the whole resolution system is locked => nothing can work properly => deadlocks
var newResolver = new ActionsResolver(
new ActivatorServiceProvider(), LoggerResolver.Current.Logger,
() => TypeFinder.FindClassesOfType<IAction>(PluginManager.Current.AssembliesToScan));
using (Umbraco.Core.ObjectResolution.Resolution.DirtyBackdoorToConfiguration)
{
ActionsResolver.Reset(false); // and do NOT reset the whole resolution!
ActionsResolver.Current = newResolver;
}
// this will reset the collection
Current.ActionCollectionBuilder.SetProducer(() => TypeFinder.FindClassesOfType<IAction>(PluginManager.Current.AssembliesToScan));
}
}
@@ -81,7 +69,7 @@ namespace Umbraco.Web._Legacy.Actions
/// <returns></returns>
public static List<string> GetJavaScriptFileReferences()
{
return ActionsResolver.Current.Actions
return Current.Actions
.Where(x => !string.IsNullOrWhiteSpace(x.JsSource))
.Select(x => x.JsSource).ToList();
//return ActionJsReference;
@@ -90,7 +78,7 @@ namespace Umbraco.Web._Legacy.Actions
/// <summary>
/// Javascript menuitems - tree contextmenu
/// Umbraco console
///
///
/// Suggestion: this method should be moved to the presentation layer.
/// </summary>
/// <param name="language"></param>
@@ -101,7 +89,7 @@ namespace Umbraco.Web._Legacy.Actions
{
string _actionJsList = "";
foreach (IAction action in ActionsResolver.Current.Actions)
foreach (IAction action in Current.Actions)
{
// Adding try/catch so this rutine doesn't fail if one of the actions fail
// Add to language JsList
@@ -139,7 +127,7 @@ namespace Umbraco.Web._Legacy.Actions
List<IAction> list = new List<IAction>();
foreach (var c in entityPermission.AssignedPermissions.Where(x => x.Length == 1).Select(x => x.ToCharArray()[0]))
{
IAction action = ActionsResolver.Current.Actions.ToList().Find(
IAction action = Current.Actions.ToList().Find(
delegate (IAction a)
{
return a.Letter == c;
@@ -162,7 +150,7 @@ namespace Umbraco.Web._Legacy.Actions
List<IAction> list = new List<IAction>();
foreach (char c in actions.ToCharArray())
{
IAction action = ActionsResolver.Current.Actions.ToList().Find(
IAction action = Current.Actions.ToList().Find(
delegate(IAction a)
{
return a.Letter == c;
@@ -190,7 +178,7 @@ namespace Umbraco.Web._Legacy.Actions
/// <returns></returns>
public static List<IAction> GetPermissionAssignable()
{
return ActionsResolver.Current.Actions.ToList().FindAll(
return Current.Actions.ToList().FindAll(
delegate(IAction a)
{
return (a.CanBePermissionAssigned);

View File

@@ -2,74 +2,83 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Umbraco.Core.Logging;
using Umbraco.Core.ObjectResolution;
using Umbraco.Core._Legacy.PackageActions;
using LightInject;
using Umbraco.Core.DependencyInjection;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// A resolver to return all IAction objects
/// </summary>
public sealed class ActionsResolver : LazyManyObjectsResolverBase<ActionsResolver, IAction>
public class ActionCollectionBuilder : ICollectionBuilder<ActionCollection, IAction>
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="serviceProvider"></param>
/// <param name="logger"></param>
/// <param name="packageActions"></param>
internal ActionsResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> packageActions)
: base(serviceProvider, logger, packageActions)
{
private static Func<IEnumerable<Type>> _producer;
public static ActionCollectionBuilder Register(IServiceContainer container)
{
// register the builder - per container
var builderLifetime = new PerContainerLifetime();
container.Register<ActionCollectionBuilder>(builderLifetime);
// get the builder, get the collection lifetime
var builder = container.GetInstance<ActionCollectionBuilder>();
var collectionLifetime = builder.CollectionLifetime;
// register the collection - special lifetime
container.Register(factory => factory.GetInstance<ActionCollectionBuilder>().CreateCollection(), collectionLifetime);
return builder;
}
/// <summary>
/// Gets the <see cref="IPackageAction"/> implementations.
/// </summary>
public IEnumerable<IAction> Actions
{
get
{
return Values;
}
}
/// <summary>
/// Gets an Action if it exists.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
internal IAction GetAction<T>()
where T : IAction
{
return Actions.SingleOrDefault(x => x.GetType() == typeof(T));
}
protected override IEnumerable<IAction> CreateInstances()
public ActionCollection CreateCollection()
{
var actions = new List<IAction>();
var foundIActions = InstanceTypes;
foreach (var type in foundIActions)
foreach (var type in _producer())
{
IAction typeInstance;
var instance = type.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static);
//if the singletone initializer is not found, try simply creating an instance of the IAction if it supports public constructors
if (instance == null)
typeInstance = ServiceProvider.GetService(type) as IAction;
else
typeInstance = instance.GetValue(null, null) as IAction;
if (typeInstance != null)
{
actions.Add(typeInstance);
}
var getter = type.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static);
var instance = getter == null
? Activator.CreateInstance(type) as IAction
: getter.GetValue(null, null) as IAction;
if (instance == null) continue;
actions.Add(instance);
}
return actions;
return new ActionCollection(actions);
}
public void SetProducer(Func<IEnumerable<Type>> producer)
{
_producer = producer;
CollectionLifetime.Reset();
}
private ResettablePerContainerLifetime CollectionLifetime { get; } = new ResettablePerContainerLifetime();
private class ResettablePerContainerLifetime : ILifetime
{
private object _instance;
public object GetInstance(Func<object> createInstance, Scope scope)
{
// not dealing with disposable instances, actions are not disposable
return _instance ?? (_instance = createInstance());
}
public void Reset()
{
_instance = null;
}
}
}
public class ActionCollection : BuilderCollectionBase<IAction>
{
public ActionCollection(IEnumerable<IAction> items)
: base(items)
{ }
internal T GetAction<T>()
where T : IAction
{
return this.OfType<T>().SingleOrDefault();
}
}
public interface IAction
@@ -91,11 +100,6 @@ namespace Umbraco.Web._Legacy.Actions
/// </summary>
public class ActionAssignDomain : IAction
{
//create singleton
#pragma warning disable 612,618
private static readonly ActionAssignDomain m_instance = new ActionAssignDomain();
#pragma warning restore 612,618
/// <summary>
/// A public constructor exists ONLY for backwards compatibility in regards to 3rd party add-ons.
/// All Umbraco assemblies should use the singleton instantiation (this.Instance)
@@ -104,12 +108,9 @@ namespace Umbraco.Web._Legacy.Actions
[Obsolete("Use the singleton instantiation instead of a constructor")]
public ActionAssignDomain() { }
public static ActionAssignDomain Instance
{
get { return m_instance; }
}
public static ActionAssignDomain Instance { get; } = new ActionAssignDomain();
#region IAction Members
#region IAction Members
public char Letter
{

View File

@@ -8,11 +8,6 @@ namespace Umbraco.Web._Legacy.Actions
/// </summary>
public class ActionAudit : IAction
{
//create singleton
#pragma warning disable 612,618
private static readonly ActionAudit m_instance = new ActionAudit();
#pragma warning restore 612,618
/// <summary>
/// A public constructor exists ONLY for backwards compatibility in regards to 3rd party add-ons.
/// All Umbraco assemblies should use the singleton instantiation (this.Instance)
@@ -21,10 +16,7 @@ namespace Umbraco.Web._Legacy.Actions
[Obsolete("Use the singleton instantiation instead of a constructor")]
public ActionAudit() { }
public static ActionAudit Instance
{
get { return m_instance; }
}
public static ActionAudit Instance { get; } = new ActionAudit();
#region IAction Members

View File

@@ -8,9 +8,6 @@ namespace Umbraco.Web._Legacy.Actions
/// </summary>
public class ActionNew : IAction
{
//create singleton
private static readonly ActionNew InnerInstance = new ActionNew();
/// <summary>
/// A public constructor exists ONLY for backwards compatibility in regards to 3rd party add-ons.
/// All Umbraco assemblies should use the singleton instantiation (this.Instance)
@@ -19,10 +16,7 @@ namespace Umbraco.Web._Legacy.Actions
[Obsolete("Use the singleton instantiation instead of a constructor")]
public ActionNew() { }
public static ActionNew Instance
{
get { return InnerInstance; }
}
public static ActionNew Instance { get; } = new ActionNew();
#region IAction Members

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Web.Script.Serialization;
using Umbraco.Core.Logging;
using Umbraco.Core;
using Umbraco.Web;
using Umbraco.Web._Legacy.Actions;
using Action = Umbraco.Web._Legacy.Actions.Action;
@@ -21,7 +22,7 @@ namespace umbraco.controls.Tree
});
List<IAction> allActions = new List<IAction>();
foreach (var a in ActionsResolver.Current.Actions)
foreach (var a in Current.Actions)
{
// NH: Added a try/catch block to this as an error in a 3rd party action can crash the whole menu initialization
try

View File

@@ -4,6 +4,7 @@ using System.Web.Script.Serialization;
using System.Text;
using Umbraco.Core;
using Umbraco.Core.Services;
using Umbraco.Web;
using Umbraco.Web._Legacy.Actions;
namespace umbraco.controls.Tree
@@ -67,7 +68,7 @@ namespace umbraco.controls.Tree
get
{
List<Type> types = new List<Type>();
foreach (var a in ActionsResolver.Current.Actions)
foreach (var a in Current.Actions)
{
types.Add(a.GetType());
}

View File

@@ -48,7 +48,7 @@ namespace umbraco.dialogs
corner.Style.Add("border", "none");
names.Cells.Add(corner);
foreach (var a in ActionsResolver.Current.Actions)
foreach (var a in Current.Actions)
{
if (a.CanBePermissionAssigned == false) continue;
@@ -77,7 +77,7 @@ namespace umbraco.dialogs
hc.Style.Add("border", "none");
names.Cells.Add(hc);
foreach (var a in ActionsResolver.Current.Actions)
foreach (var a in Current.Actions)
{
var chk = new CheckBox
{

View File

@@ -43,7 +43,7 @@ namespace umbraco.dialogs
node = Services.EntityService.Get(int.Parse(Request.GetItemAsString("id")));
var actionList = ActionsResolver.Current.Actions;
var actionList = Current.Actions;
foreach (var a in actionList)
{

View File

@@ -10,6 +10,7 @@ using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using Umbraco.Core;
using Umbraco.Core.Services;
using Umbraco.Web;
using Umbraco.Web._Legacy.Actions;
using Action = Umbraco.Web._Legacy.Actions.Action;
@@ -41,7 +42,7 @@ namespace umbraco.presentation.umbraco.dialogs
action = action.ToLower();
if (action == "new")
action = "create";
var actions = ActionsResolver.Current.Actions;
var actions = Current.Actions;
foreach (var a in actions)
{
return Services.TextService.Localize(action);