From eeb9d3c01e4dd0e5e93e6cbe98cc5693d2a5812c Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Sun, 2 Jun 2024 23:17:49 +0200 Subject: [PATCH 1/4] Add IAsyncComponent --- src/Umbraco.Core/Composing/IAsyncComponent.cs | 38 ++++++++++++++++ src/Umbraco.Core/Composing/IComponent.cs | 43 +++++++++++++------ 2 files changed, 68 insertions(+), 13 deletions(-) create mode 100644 src/Umbraco.Core/Composing/IAsyncComponent.cs diff --git a/src/Umbraco.Core/Composing/IAsyncComponent.cs b/src/Umbraco.Core/Composing/IAsyncComponent.cs new file mode 100644 index 000000000000..50990d02b7fb --- /dev/null +++ b/src/Umbraco.Core/Composing/IAsyncComponent.cs @@ -0,0 +1,38 @@ +namespace Umbraco.Cms.Core.Composing; + +/// +/// Represents a component. +/// +/// +/// +/// Components are created by DI and therefore must have a public constructor. +/// +/// +/// All components are terminated in reverse order when Umbraco terminates, and disposable components are disposed. +/// +/// +/// The Dispose method may be invoked more than once, and components should ensure they support this. +/// +/// +public interface IAsyncComponent +{ + /// + /// Initializes the component. + /// + /// If set to true indicates Umbraco is restarting. + /// The cancellation token. Cancellation indicates that the start process has been aborted. + /// + /// A representing the asynchronous operation. + /// + Task InitializeAsync(bool isRestarting, CancellationToken cancellationToken); + + /// + /// Terminates the component. + /// + /// If set to true indicates Umbraco is restarting. + /// The cancellation token. Cancellation indicates that the shutdown process should no longer be graceful. + /// + /// A representing the asynchronous operation. + /// + Task TerminateAsync(bool isRestarting, CancellationToken cancellationToken); +} diff --git a/src/Umbraco.Core/Composing/IComponent.cs b/src/Umbraco.Core/Composing/IComponent.cs index d5655f8a1f81..28de98fbf709 100644 --- a/src/Umbraco.Core/Composing/IComponent.cs +++ b/src/Umbraco.Core/Composing/IComponent.cs @@ -1,28 +1,45 @@ namespace Umbraco.Cms.Core.Composing; /// -/// Represents a component. +/// Represents a component. /// /// -/// Components are created by DI and therefore must have a public constructor. -/// -/// All components are terminated in reverse order when Umbraco terminates, and -/// disposable components are disposed. -/// -/// -/// The Dispose method may be invoked more than once, and components -/// should ensure they support this. -/// +/// +/// Components are created by DI and therefore must have a public constructor. +/// +/// +/// All components are terminated in reverse order when Umbraco terminates, and disposable components are disposed. +/// +/// +/// The Dispose method may be invoked more than once, and components should ensure they support this. +/// /// -public interface IComponent +[Obsolete("Use IAsyncComponent instead. This interface will be removed in a future version.")] +public interface IComponent : IAsyncComponent { /// - /// Initializes the component. + /// Initializes the component. /// void Initialize(); /// - /// Terminates the component. + /// Terminates the component. /// void Terminate(); + + /// + Task IAsyncComponent.InitializeAsync(bool isRestarting, CancellationToken cancellationToken) + { + Initialize(); + + return Task.CompletedTask; + } + + /// + Task IAsyncComponent.TerminateAsync(bool isRestarting, CancellationToken cancellationToken) + { + Terminate(); + + return Task.CompletedTask; + } } From 9264ed46eb44ba1090b0c7fcf57f48abb7bd1973 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Sun, 2 Jun 2024 23:25:23 +0200 Subject: [PATCH 2/4] Rewrite to use IAsyncComposer --- .../Composing/ComponentCollection.cs | 48 ++++++++++--------- .../Composing/ComponentCollectionBuilder.cs | 22 ++++----- .../Composing/ComponentComposer.cs | 23 +++++---- .../UmbracoBuilder.CollectionBuilders.cs | 2 +- .../Extensions/ObjectExtensions.cs | 19 +++++++- .../UmbracoApplicationStartingNotification.cs | 30 ++++++------ .../UmbracoApplicationStoppingNotification.cs | 19 ++++---- .../Runtime/CoreRuntime.cs | 4 +- .../Umbraco.Core/Components/ComponentTests.cs | 20 ++++---- 9 files changed, 104 insertions(+), 83 deletions(-) diff --git a/src/Umbraco.Core/Composing/ComponentCollection.cs b/src/Umbraco.Core/Composing/ComponentCollection.cs index 506eb2313483..858d27aac6c5 100644 --- a/src/Umbraco.Core/Composing/ComponentCollection.cs +++ b/src/Umbraco.Core/Composing/ComponentCollection.cs @@ -5,59 +5,61 @@ namespace Umbraco.Cms.Core.Composing; /// -/// Represents the collection of implementations. +/// Represents the collection of implementations. /// -public class ComponentCollection : BuilderCollectionBase +public class ComponentCollection : BuilderCollectionBase { private const int LogThresholdMilliseconds = 100; - private readonly ILogger _logger; private readonly IProfilingLogger _profilingLogger; + private readonly ILogger _logger; - public ComponentCollection(Func> items, IProfilingLogger profilingLogger, ILogger logger) + public ComponentCollection(Func> items, IProfilingLogger profilingLogger, ILogger logger) : base(items) { _profilingLogger = profilingLogger; _logger = logger; } - public void Initialize() + public async Task InitializeAsync(bool isRestarting, CancellationToken cancellationToken) { - using (!_profilingLogger.IsEnabled(Logging.LogLevel.Debug) ? null : _profilingLogger.DebugDuration( - $"Initializing. (log components when >{LogThresholdMilliseconds}ms)", "Initialized.")) + using (_profilingLogger.IsEnabled(Logging.LogLevel.Debug) is false + ? null + : _profilingLogger.DebugDuration($"Initializing. (log components when >{LogThresholdMilliseconds}ms)", "Initialized.")) { - foreach (IComponent component in this) + foreach (IAsyncComponent component in this) { Type componentType = component.GetType(); - using (!_profilingLogger.IsEnabled(Logging.LogLevel.Debug) ? null : _profilingLogger.DebugDuration( - $"Initializing {componentType.FullName}.", - $"Initialized {componentType.FullName}.", - thresholdMilliseconds: LogThresholdMilliseconds)) + + using (_profilingLogger.IsEnabled(Logging.LogLevel.Debug) is false + ? null : + _profilingLogger.DebugDuration($"Initializing {componentType.FullName}.", $"Initialized {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds)) { - component.Initialize(); + await component.InitializeAsync(isRestarting, cancellationToken); } } } } - public void Terminate() + public async Task TerminateAsync(bool isRestarting, CancellationToken cancellationToken) { - using (!_profilingLogger.IsEnabled(Logging.LogLevel.Debug) ? null : _profilingLogger.DebugDuration( - $"Terminating. (log components when >{LogThresholdMilliseconds}ms)", "Terminated.")) + using (!_profilingLogger.IsEnabled(Logging.LogLevel.Debug) + ? null + : _profilingLogger.DebugDuration($"Terminating. (log components when >{LogThresholdMilliseconds}ms)", "Terminated.")) { // terminate components in reverse order - foreach (IComponent component in this.Reverse()) + foreach (IAsyncComponent component in this.Reverse()) { Type componentType = component.GetType(); - using (!_profilingLogger.IsEnabled(Logging.LogLevel.Debug) ? null : _profilingLogger.DebugDuration( - $"Terminating {componentType.FullName}.", - $"Terminated {componentType.FullName}.", - thresholdMilliseconds: LogThresholdMilliseconds)) + + using (_profilingLogger.IsEnabled(Logging.LogLevel.Debug) is false + ? null + : _profilingLogger.DebugDuration($"Terminating {componentType.FullName}.", $"Terminated {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds)) { try { - component.Terminate(); - component.DisposeIfDisposable(); + await component.TerminateAsync(isRestarting, cancellationToken); + await component.DisposeAsyncIfDisposable(); } catch (Exception ex) { diff --git a/src/Umbraco.Core/Composing/ComponentCollectionBuilder.cs b/src/Umbraco.Core/Composing/ComponentCollectionBuilder.cs index 04461db4fbd0..f4cdb802387e 100644 --- a/src/Umbraco.Core/Composing/ComponentCollectionBuilder.cs +++ b/src/Umbraco.Core/Composing/ComponentCollectionBuilder.cs @@ -4,35 +4,33 @@ namespace Umbraco.Cms.Core.Composing; /// -/// Builds a . +/// Builds a . /// -public class - ComponentCollectionBuilder : OrderedCollectionBuilderBase +public class ComponentCollectionBuilder : OrderedCollectionBuilderBase { private const int LogThresholdMilliseconds = 100; protected override ComponentCollectionBuilder This => this; - protected override IEnumerable CreateItems(IServiceProvider factory) + protected override IEnumerable CreateItems(IServiceProvider factory) { IProfilingLogger logger = factory.GetRequiredService(); - using (!logger.IsEnabled(Logging.LogLevel.Debug) ? null : logger.DebugDuration( - $"Creating components. (log when >{LogThresholdMilliseconds}ms)", "Created.")) + using (logger.IsEnabled(Logging.LogLevel.Debug) is false + ? null + : logger.DebugDuration($"Creating components. (log when >{LogThresholdMilliseconds}ms)", "Created.")) { return base.CreateItems(factory); } } - protected override IComponent CreateItem(IServiceProvider factory, Type itemType) + protected override IAsyncComponent CreateItem(IServiceProvider factory, Type itemType) { IProfilingLogger logger = factory.GetRequiredService(); - using (!logger.IsEnabled(Logging.LogLevel.Debug) ? null : logger.DebugDuration( - $"Creating {itemType.FullName}.", - $"Created {itemType.FullName}.", - thresholdMilliseconds: LogThresholdMilliseconds)) + using (logger.IsEnabled(Logging.LogLevel.Debug) is false + ? null : + logger.DebugDuration($"Creating {itemType.FullName}.", $"Created {itemType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds)) { return base.CreateItem(factory, itemType); } diff --git a/src/Umbraco.Core/Composing/ComponentComposer.cs b/src/Umbraco.Core/Composing/ComponentComposer.cs index 2a9641e64b5a..6beee43766cb 100644 --- a/src/Umbraco.Core/Composing/ComponentComposer.cs +++ b/src/Umbraco.Core/Composing/ComponentComposer.cs @@ -1,18 +1,23 @@ -using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; namespace Umbraco.Cms.Core.Composing; /// -/// Provides a base class for composers which compose a component. +/// Provides a composer that appends a component. /// -/// The type of the component +/// The type of the component. +/// +/// Thanks to this class, a component that does not compose anything can be registered with one line: +/// +/// { } +/// ]]> +/// +/// public abstract class ComponentComposer : IComposer - where TComponent : IComponent + where TComponent : IAsyncComponent { /// - public virtual void Compose(IUmbracoBuilder builder) => builder.Components().Append(); - - // note: thanks to this class, a component that does not compose anything can be - // registered with one line: - // public class MyComponentComposer : ComponentComposer { } + public virtual void Compose(IUmbracoBuilder builder) + => builder.Components().Append(); } diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.CollectionBuilders.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.CollectionBuilders.cs index af42e0993630..e1536f9a4d8a 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.CollectionBuilders.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.CollectionBuilders.cs @@ -21,7 +21,7 @@ public static partial class UmbracoBuilderExtensions /// The builder. /// public static IUmbracoBuilder AddComponent(this IUmbracoBuilder builder) - where T : IComponent + where T : IAsyncComponent { builder.Components().Append(); diff --git a/src/Umbraco.Core/Extensions/ObjectExtensions.cs b/src/Umbraco.Core/Extensions/ObjectExtensions.cs index f0f10d8cc653..58f6e445d721 100644 --- a/src/Umbraco.Core/Extensions/ObjectExtensions.cs +++ b/src/Umbraco.Core/Extensions/ObjectExtensions.cs @@ -41,8 +41,9 @@ public static class ObjectExtensions public static IEnumerable AsEnumerableOfOne(this T input) => Enumerable.Repeat(input, 1); /// + /// Disposes the object if it implements . /// - /// + /// The object. public static void DisposeIfDisposable(this object input) { if (input is IDisposable disposable) @@ -51,6 +52,22 @@ public static void DisposeIfDisposable(this object input) } } + /// + /// Disposes the object if it implements or . + /// + /// The object. + public static async Task DisposeAsyncIfDisposable(this object input) + { + if (input is IAsyncDisposable disposable) + { + await disposable.DisposeAsync(); + } + else + { + input.DisposeIfDisposable(); + } + } + /// /// Provides a shortcut way of safely casting an input when you cannot guarantee the is /// an instance type (i.e., when the C# AS keyword is not applicable). diff --git a/src/Umbraco.Core/Notifications/UmbracoApplicationStartingNotification.cs b/src/Umbraco.Core/Notifications/UmbracoApplicationStartingNotification.cs index 9172359eb0aa..63c733f3cb77 100644 --- a/src/Umbraco.Core/Notifications/UmbracoApplicationStartingNotification.cs +++ b/src/Umbraco.Core/Notifications/UmbracoApplicationStartingNotification.cs @@ -1,28 +1,26 @@ namespace Umbraco.Cms.Core.Notifications; /// -/// Notification that occurs at the very end of the Umbraco boot process (after all s are -/// initialized). +/// Notification that occurs at the very end of the Umbraco boot process (after all components are initialized). +/// +public class UmbracoApplicationStartingNotification : IUmbracoApplicationLifetimeNotification +{ + /// + /// Initializes a new instance of the class. /// - /// - public class UmbracoApplicationStartingNotification : IUmbracoApplicationLifetimeNotification + /// The runtime level + /// Indicates whether Umbraco is restarting. + public UmbracoApplicationStartingNotification(RuntimeLevel runtimeLevel, bool isRestarting) { - /// - /// Initializes a new instance of the class. - /// - /// The runtime level - /// Indicates whether Umbraco is restarting. - public UmbracoApplicationStartingNotification(RuntimeLevel runtimeLevel, bool isRestarting) - { - RuntimeLevel = runtimeLevel; - IsRestarting = isRestarting; - } + RuntimeLevel = runtimeLevel; + IsRestarting = isRestarting; + } /// - /// Gets the runtime level. + /// Gets the runtime level. /// /// - /// The runtime level. + /// The runtime level. /// public RuntimeLevel RuntimeLevel { get; } diff --git a/src/Umbraco.Core/Notifications/UmbracoApplicationStoppingNotification.cs b/src/Umbraco.Core/Notifications/UmbracoApplicationStoppingNotification.cs index d33233d43851..43058fe27f09 100644 --- a/src/Umbraco.Core/Notifications/UmbracoApplicationStoppingNotification.cs +++ b/src/Umbraco.Core/Notifications/UmbracoApplicationStoppingNotification.cs @@ -1,17 +1,16 @@ namespace Umbraco.Cms.Core.Notifications; - +/// +/// Notification that occurs when Umbraco is shutting down (after all components are terminated). +/// +public class UmbracoApplicationStoppingNotification : IUmbracoApplicationLifetimeNotification +{ /// - /// Notification that occurs when Umbraco is shutting down (after all s are terminated). + /// Initializes a new instance of the class. /// - /// - public class UmbracoApplicationStoppingNotification : IUmbracoApplicationLifetimeNotification - { - /// - /// Initializes a new instance of the class. - /// - /// Indicates whether Umbraco is restarting. - public UmbracoApplicationStoppingNotification(bool isRestarting) => IsRestarting = isRestarting; + /// Indicates whether Umbraco is restarting. + public UmbracoApplicationStoppingNotification(bool isRestarting) + => IsRestarting = isRestarting; /// public bool IsRestarting { get; } diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs index 42f7f6de3ffe..2e4604904238 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs @@ -222,7 +222,7 @@ private async Task StartAsync(CancellationToken cancellationToken, bool isRestar } // Initialize the components - _components.Initialize(); + await _components.InitializeAsync(isRestarting, cancellationToken); await _eventAggregator.PublishAsync(new UmbracoApplicationStartingNotification(State.Level, isRestarting), cancellationToken); @@ -236,7 +236,7 @@ private async Task StartAsync(CancellationToken cancellationToken, bool isRestar private async Task StopAsync(CancellationToken cancellationToken, bool isRestarting) { - _components.Terminate(); + await _components.TerminateAsync(isRestarting, cancellationToken); await _eventAggregator.PublishAsync(new UmbracoApplicationStoppingNotification(isRestarting), cancellationToken); } diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs index ca47bfbd9707..94bff4a0c904 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs @@ -80,7 +80,9 @@ private static IServiceProvider MockFactory(Action> setup Options.Create(new ContentSettings())); var eventAggregator = Mock.Of(); var scopeProvider = new ScopeProvider( - new AmbientScopeStack(), new AmbientScopeContextStack(),Mock.Of(), + new AmbientScopeStack(), + new AmbientScopeContextStack(), + Mock.Of(), f, fs, new TestOptionsMonitor(coreDebug), @@ -113,7 +115,7 @@ private static IServiceProvider MockFactory(Action> setup Mock.Of()); [Test] - public void Boot1A() + public async Task Boot1A() { var register = MockRegister(); var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); @@ -157,7 +159,7 @@ public void Boot1A() { return Mock.Of>(); } - + if (type == typeof(ILogger)) { return Mock.Of>(); @@ -176,9 +178,9 @@ public void Boot1A() var components = builder.CreateCollection(factory); Assert.IsEmpty(components); - components.Initialize(); + await components.InitializeAsync(false, default); Assert.IsEmpty(Initialized); - components.Terminate(); + await components.TerminateAsync(false, default); Assert.IsEmpty(Terminated); } @@ -277,7 +279,7 @@ public void BrokenRequired() } [Test] - public void Initialize() + public async Task Initialize() { Composed.Clear(); Initialized.Clear(); @@ -324,7 +326,7 @@ public void Initialize() { return Mock.Of>(); } - + if (type == typeof(IServiceProviderIsService)) { return Mock.Of(); @@ -347,11 +349,11 @@ public void Initialize() var components = builder.CreateCollection(factory); Assert.IsEmpty(Initialized); - components.Initialize(); + await components.InitializeAsync(false, default); AssertTypeArray(TypeArray(), Initialized); Assert.IsEmpty(Terminated); - components.Terminate(); + await components.TerminateAsync(false, default); AssertTypeArray(TypeArray(), Terminated); } From 31b267ebdd34ce74e82498ecd2d7271f09124f79 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Sun, 2 Jun 2024 23:26:26 +0200 Subject: [PATCH 3/4] Add AsyncComponentBase and RuntimeAsyncComponentBase --- .../Composing/AsyncComponentBase.cs | 55 +++++++++++++++++++ .../Composing/RuntimeAsyncComponentBase.cs | 23 ++++++++ 2 files changed, 78 insertions(+) create mode 100644 src/Umbraco.Core/Composing/AsyncComponentBase.cs create mode 100644 src/Umbraco.Core/Composing/RuntimeAsyncComponentBase.cs diff --git a/src/Umbraco.Core/Composing/AsyncComponentBase.cs b/src/Umbraco.Core/Composing/AsyncComponentBase.cs new file mode 100644 index 000000000000..5ba3dd168df4 --- /dev/null +++ b/src/Umbraco.Core/Composing/AsyncComponentBase.cs @@ -0,0 +1,55 @@ +namespace Umbraco.Cms.Core.Composing; + +/// +/// +/// By default, the component will not execute if Umbraco is restarting. +/// +public abstract class AsyncComponentBase : IAsyncComponent +{ + /// + public async Task InitializeAsync(bool isRestarting, CancellationToken cancellationToken) + { + if (CanExecute(isRestarting)) + { + await InitializeAsync(cancellationToken).ConfigureAwait(false); + } + } + + /// + public async Task TerminateAsync(bool isRestarting, CancellationToken cancellationToken) + { + if (CanExecute(isRestarting)) + { + await TerminateAsync(cancellationToken).ConfigureAwait(false); + } + } + + /// + /// Determines whether the component can execute. + /// + /// If set to true indicates Umbraco is restarting. + /// + /// true if the component can execute; otherwise, false. + /// + protected virtual bool CanExecute(bool isRestarting) + => isRestarting is false; + + /// + /// Initializes the component. + /// + /// The cancellation token. Cancellation indicates that the start process has been aborted. + /// + /// A representing the asynchronous operation. + /// + protected abstract Task InitializeAsync(CancellationToken cancellationToken); + + /// + /// Terminates the component. + /// + /// The cancellation token. Cancellation indicates that the shutdown process should no longer be graceful. + /// + /// A representing the asynchronous operation. + /// + protected virtual Task TerminateAsync(CancellationToken cancellationToken) + => Task.CompletedTask; +} diff --git a/src/Umbraco.Core/Composing/RuntimeAsyncComponentBase.cs b/src/Umbraco.Core/Composing/RuntimeAsyncComponentBase.cs new file mode 100644 index 000000000000..d4e326e05810 --- /dev/null +++ b/src/Umbraco.Core/Composing/RuntimeAsyncComponentBase.cs @@ -0,0 +1,23 @@ +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Core.Composing; + +/// +/// +/// By default, the component will not execute if Umbraco is restarting or the runtime level is not . +/// +public abstract class RuntimeAsyncComponentBase : AsyncComponentBase +{ + private readonly IRuntimeState _runtimeState; + + /// + /// Initializes a new instance of the class. + /// + /// State of the Umbraco runtime. + protected RuntimeAsyncComponentBase(IRuntimeState runtimeState) + => _runtimeState = runtimeState; + + /// + protected override bool CanExecute(bool isRestarting) + => base.CanExecute(isRestarting) && _runtimeState.Level == RuntimeLevel.Run; +} From 30047cf0fc065b74aad666af48ea5f5f7e391e7c Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 11 Sep 2024 23:08:45 +0200 Subject: [PATCH 4/4] Remove manual disposing of components on restart --- .../Composing/ComponentCollection.cs | 1 - src/Umbraco.Core/Composing/IAsyncComponent.cs | 3 --- src/Umbraco.Core/Composing/IComponent.cs | 15 +-------------- src/Umbraco.Core/Extensions/ObjectExtensions.cs | 16 ---------------- 4 files changed, 1 insertion(+), 34 deletions(-) diff --git a/src/Umbraco.Core/Composing/ComponentCollection.cs b/src/Umbraco.Core/Composing/ComponentCollection.cs index 858d27aac6c5..ba49a6f48227 100644 --- a/src/Umbraco.Core/Composing/ComponentCollection.cs +++ b/src/Umbraco.Core/Composing/ComponentCollection.cs @@ -59,7 +59,6 @@ public async Task TerminateAsync(bool isRestarting, CancellationToken cancellati try { await component.TerminateAsync(isRestarting, cancellationToken); - await component.DisposeAsyncIfDisposable(); } catch (Exception ex) { diff --git a/src/Umbraco.Core/Composing/IAsyncComponent.cs b/src/Umbraco.Core/Composing/IAsyncComponent.cs index 50990d02b7fb..b84e95887990 100644 --- a/src/Umbraco.Core/Composing/IAsyncComponent.cs +++ b/src/Umbraco.Core/Composing/IAsyncComponent.cs @@ -10,9 +10,6 @@ namespace Umbraco.Cms.Core.Composing; /// /// All components are terminated in reverse order when Umbraco terminates, and disposable components are disposed. /// -/// -/// The Dispose method may be invoked more than once, and components should ensure they support this. -/// /// public interface IAsyncComponent { diff --git a/src/Umbraco.Core/Composing/IComponent.cs b/src/Umbraco.Core/Composing/IComponent.cs index 28de98fbf709..2c3b9b7e4f81 100644 --- a/src/Umbraco.Core/Composing/IComponent.cs +++ b/src/Umbraco.Core/Composing/IComponent.cs @@ -1,19 +1,6 @@ namespace Umbraco.Cms.Core.Composing; -/// -/// Represents a component. -/// -/// -/// -/// Components are created by DI and therefore must have a public constructor. -/// -/// -/// All components are terminated in reverse order when Umbraco terminates, and disposable components are disposed. -/// -/// -/// The Dispose method may be invoked more than once, and components should ensure they support this. -/// -/// +/// [Obsolete("Use IAsyncComponent instead. This interface will be removed in a future version.")] public interface IComponent : IAsyncComponent { diff --git a/src/Umbraco.Core/Extensions/ObjectExtensions.cs b/src/Umbraco.Core/Extensions/ObjectExtensions.cs index 58f6e445d721..1ce15bdc72c5 100644 --- a/src/Umbraco.Core/Extensions/ObjectExtensions.cs +++ b/src/Umbraco.Core/Extensions/ObjectExtensions.cs @@ -52,22 +52,6 @@ public static void DisposeIfDisposable(this object input) } } - /// - /// Disposes the object if it implements or . - /// - /// The object. - public static async Task DisposeAsyncIfDisposable(this object input) - { - if (input is IAsyncDisposable disposable) - { - await disposable.DisposeAsync(); - } - else - { - input.DisposeIfDisposable(); - } - } - /// /// Provides a shortcut way of safely casting an input when you cannot guarantee the is /// an instance type (i.e., when the C# AS keyword is not applicable).