refactor(core): inject ContentPermissionManager into ContentService

Phase 6: Add constructor parameter and lazy fallback for ContentPermissionManager.

Changes:
- Add private fields _permissionManager and _permissionManagerLazy to ContentService
- Add PermissionManager property accessor with null safety check
- Update primary constructor to accept ContentPermissionManager as parameter 23
- Update all obsolete constructors with lazy resolution via StaticServiceProvider
- Update DI factory in UmbracoBuilder to pass ContentPermissionManager
- Make ContentPermissionManager public for DI compatibility

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-24 14:45:55 +00:00
parent 08dadc7545
commit 08b6fd3576
3 changed files with 34 additions and 5 deletions

View File

@@ -328,7 +328,8 @@ namespace Umbraco.Cms.Core.DependencyInjection
sp.GetRequiredService<IContentQueryOperationService>(),
sp.GetRequiredService<IContentVersionOperationService>(),
sp.GetRequiredService<IContentMoveOperationService>(),
sp.GetRequiredService<IContentPublishOperationService>()));
sp.GetRequiredService<IContentPublishOperationService>(),
sp.GetRequiredService<ContentPermissionManager>()));
Services.AddUnique<IContentBlueprintEditingService, ContentBlueprintEditingService>();
Services.AddUnique<IContentEditingService, ContentEditingService>();
Services.AddUnique<IContentPublishingService, ContentPublishingService>();

View File

@@ -13,11 +13,11 @@ namespace Umbraco.Cms.Core.Services;
/// </summary>
/// <remarks>
/// <para>
/// This is an internal class that encapsulates permission operations extracted from ContentService
/// This class encapsulates permission operations extracted from ContentService
/// as part of the ContentService refactoring initiative (Phase 6).
/// </para>
/// <para>
/// <strong>Design Decision:</strong> This class is internal (not public interface) because:
/// <strong>Design Decision:</strong> This class is public for DI but not intended for direct external use:
/// <list type="bullet">
/// <item><description>Permission operations are tightly coupled to content entities</description></item>
/// <item><description>They don't require independent testability beyond ContentService tests</description></item>
@@ -29,7 +29,7 @@ namespace Umbraco.Cms.Core.Services;
/// materialized collection (not deferred), so scope disposal before enumeration is safe.
/// </para>
/// </remarks>
internal sealed class ContentPermissionManager
public sealed class ContentPermissionManager
{
private readonly ICoreScopeProvider _scopeProvider;
private readonly IDocumentRepository _documentRepository;

View File

@@ -67,6 +67,10 @@ public class ContentService : RepositoryService, IContentService
private readonly IContentPublishOperationService? _publishOperationService;
private readonly Lazy<IContentPublishOperationService>? _publishOperationServiceLazy;
// Permission manager field (for Phase 6 extracted permission operations)
private readonly ContentPermissionManager? _permissionManager;
private readonly Lazy<ContentPermissionManager>? _permissionManagerLazy;
/// <summary>
/// Gets the query operation service.
/// </summary>
@@ -99,6 +103,14 @@ public class ContentService : RepositoryService, IContentService
_publishOperationService ?? _publishOperationServiceLazy?.Value
?? throw new InvalidOperationException("PublishOperationService not initialized. Ensure the service is properly injected via constructor.");
/// <summary>
/// Gets the permission manager.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown if the manager was not properly initialized.</exception>
private ContentPermissionManager PermissionManager =>
_permissionManager ?? _permissionManagerLazy?.Value
?? throw new InvalidOperationException("PermissionManager not initialized. Ensure the manager is properly injected via constructor.");
#region Constructors
[Microsoft.Extensions.DependencyInjection.ActivatorUtilitiesConstructor]
@@ -124,7 +136,8 @@ public class ContentService : RepositoryService, IContentService
IContentQueryOperationService queryOperationService, // NEW PARAMETER - Phase 2 query operations
IContentVersionOperationService versionOperationService, // NEW PARAMETER - Phase 3 version operations
IContentMoveOperationService moveOperationService, // NEW PARAMETER - Phase 4 move operations
IContentPublishOperationService publishOperationService) // NEW PARAMETER - Phase 5 publish operations
IContentPublishOperationService publishOperationService, // NEW PARAMETER - Phase 5 publish operations
ContentPermissionManager permissionManager) // NEW PARAMETER - Phase 6 permission operations
: base(provider, loggerFactory, eventMessagesFactory)
{
_documentRepository = documentRepository;
@@ -169,6 +182,11 @@ public class ContentService : RepositoryService, IContentService
ArgumentNullException.ThrowIfNull(publishOperationService);
_publishOperationService = publishOperationService;
_publishOperationServiceLazy = null; // Not needed when directly injected
// Phase 6: Permission manager (direct injection)
ArgumentNullException.ThrowIfNull(permissionManager);
_permissionManager = permissionManager;
_permissionManagerLazy = null; // Not needed when directly injected
}
[Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")]
@@ -240,6 +258,11 @@ public class ContentService : RepositoryService, IContentService
_publishOperationServiceLazy = new Lazy<IContentPublishOperationService>(() =>
StaticServiceProvider.Instance.GetRequiredService<IContentPublishOperationService>(),
LazyThreadSafetyMode.ExecutionAndPublication);
// Phase 6: Lazy resolution of ContentPermissionManager
_permissionManagerLazy = new Lazy<ContentPermissionManager>(() =>
StaticServiceProvider.Instance.GetRequiredService<ContentPermissionManager>(),
LazyThreadSafetyMode.ExecutionAndPublication);
}
[Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")]
@@ -310,6 +333,11 @@ public class ContentService : RepositoryService, IContentService
_publishOperationServiceLazy = new Lazy<IContentPublishOperationService>(() =>
StaticServiceProvider.Instance.GetRequiredService<IContentPublishOperationService>(),
LazyThreadSafetyMode.ExecutionAndPublication);
// Phase 6: Lazy resolution of ContentPermissionManager
_permissionManagerLazy = new Lazy<ContentPermissionManager>(() =>
StaticServiceProvider.Instance.GetRequiredService<ContentPermissionManager>(),
LazyThreadSafetyMode.ExecutionAndPublication);
}
#endregion