Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 56 additions & 2 deletions src/Umbraco.Core/Routing/NewDefaultUrlProvider.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Globalization;

Check notice on line 1 in src/Umbraco.Core/Routing/NewDefaultUrlProvider.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

✅ Getting better: Overall Code Complexity

The mean cyclomatic complexity decreases from 5.11 to 4.45, threshold = 4. This file has many conditional statements (e.g. if, for, while) across its implementation, leading to lower code health. Avoid adding more conditionals.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Expand Down Expand Up @@ -28,6 +28,7 @@
private readonly ILogger<DefaultUrlProvider> _logger;
private readonly ISiteDomainMapper _siteDomainMapper;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IUmbracoContextFactory _umbracoContextFactory;
private readonly UriUtility _uriUtility;
private RequestHandlerSettings _requestSettings;
private readonly ILanguageService _languageService;
Expand All @@ -44,6 +45,7 @@
ILogger<DefaultUrlProvider> logger,
ISiteDomainMapper siteDomainMapper,
IUmbracoContextAccessor umbracoContextAccessor,
IUmbracoContextFactory umbracoContextFactory,
UriUtility uriUtility,
#pragma warning disable CS0618 // Type or member is obsolete
#pragma warning disable IDE0060 // Remove unused parameter
Expand All @@ -62,6 +64,7 @@
_logger = logger;
_siteDomainMapper = siteDomainMapper;
_umbracoContextAccessor = umbracoContextAccessor;
_umbracoContextFactory = umbracoContextFactory;
_uriUtility = uriUtility;
_publishedContentCache = publishedContentCache;
_domainCache = domainCache;
Expand All @@ -74,6 +77,46 @@
requestSettings.OnChange(x => _requestSettings = x);
}

/// <summary>
/// Initializes a new instance of the <see cref="NewDefaultUrlProvider"/> class.
/// </summary>
[Obsolete("Use the non-obsolete constructor. Scheduled for removal in V18.")]
public NewDefaultUrlProvider(
IOptionsMonitor<RequestHandlerSettings> requestSettings,
ILogger<DefaultUrlProvider> logger,
ISiteDomainMapper siteDomainMapper,
IUmbracoContextAccessor umbracoContextAccessor,
UriUtility uriUtility,
#pragma warning disable CS0618 // Type or member is obsolete
#pragma warning disable IDE0060 // Remove unused parameter
ILocalizationService localizationService,
#pragma warning restore IDE0060 // Remove unused parameter
#pragma warning restore CS0618 // Type or member is obsolete
IPublishedContentCache publishedContentCache,
IDomainCache domainCache,
IIdKeyMap idKeyMap,
IDocumentUrlService documentUrlService,
IDocumentNavigationQueryService navigationQueryService,
IPublishedContentStatusFilteringService publishedContentStatusFilteringService,
ILanguageService languageService)
: this(
requestSettings,
logger,
siteDomainMapper,
umbracoContextAccessor,
StaticServiceProvider.Instance.GetRequiredService<IUmbracoContextFactory>(),
uriUtility,
localizationService,
publishedContentCache,
domainCache,
idKeyMap,
documentUrlService,
navigationQueryService,
publishedContentStatusFilteringService,
languageService)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="NewDefaultUrlProvider"/> class.
/// </summary>
Expand Down Expand Up @@ -223,7 +266,7 @@

private string GetLegacyRouteFormatById(Guid key, string? culture)
{
var isDraft = _umbracoContextAccessor.GetRequiredUmbracoContext().InPreviewMode;
var isDraft = GetRequiredUmbracoContext().InPreviewMode;
return _documentUrlService.GetLegacyRouteFormat(key, culture, isDraft);
}

Expand All @@ -240,7 +283,7 @@
// this document will still not always be in the memory cache. And thus we have to hit the DB
// We have the published content now, so we can check if the culture is published, and thus avoid the DB hit.
string route;
var isDraft = _umbracoContextAccessor.GetRequiredUmbracoContext().InPreviewMode;
var isDraft = GetRequiredUmbracoContext().InPreviewMode;
if(isDraft is false && string.IsNullOrWhiteSpace(culture) is false && content.Cultures.Any() && content.IsInvariantOrHasCulture(culture) is false)
{
route = "#";
Expand Down Expand Up @@ -368,4 +411,15 @@
var path = path1.TrimEnd(Constants.CharArrays.ForwardSlash) + path2;
return path == "/" ? path : path.TrimEnd(Constants.CharArrays.ForwardSlash);
}

private IUmbracoContext GetRequiredUmbracoContext()
{
if (_umbracoContextAccessor.TryGetUmbracoContext(out IUmbracoContext? umbracoContext))
{
return umbracoContext;
}

using UmbracoContextReference ctx = _umbracoContextFactory.EnsureUmbracoContext();
return ctx.UmbracoContext;
}
}
76 changes: 57 additions & 19 deletions src/Umbraco.Core/Routing/UrlProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,19 @@
/// </summary>
public class UrlProvider : IPublishedUrlProvider
{
#region Ctor and configuration
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IUmbracoContextFactory _umbracoContextFactory;
private readonly IEnumerable<IUrlProvider> _urlProviders;
private readonly IEnumerable<IMediaUrlProvider> _mediaUrlProviders;
private readonly IVariationContextAccessor _variationContextAccessor;
private readonly IDocumentNavigationQueryService _navigationQueryService;
private readonly IPublishedContentStatusFilteringService _publishedContentStatusFilteringService;

/// <summary>
/// Initializes a new instance of the <see cref="UrlProvider"/> class with an Umbraco context and a list of URL providers.
/// </summary>
/// <param name="umbracoContextAccessor">The Umbraco context accessor.</param>
/// <param name="umbracoContextFactory">The Umbraco context factory.</param>
/// <param name="routingSettings">Routing settings.</param>
/// <param name="urlProviders">The list of URL providers.</param>
/// <param name="mediaUrlProviders">The list of media URL providers.</param>
Expand All @@ -29,22 +36,49 @@
/// <param name="publishedContentStatusFilteringService"></param>
public UrlProvider(
IUmbracoContextAccessor umbracoContextAccessor,
IUmbracoContextFactory umbracoContextFactory,
IOptions<WebRoutingSettings> routingSettings,
UrlProviderCollection urlProviders,
MediaUrlProviderCollection mediaUrlProviders,
IVariationContextAccessor variationContextAccessor,
IPublishedContentCache contentCache, // Not used, but necessary to avoid ambiguous constructor.
IDocumentNavigationQueryService navigationQueryService,
IPublishStatusQueryService publishStatusQueryService, // Not used, but necessary to avoid ambiguous constructor.
IPublishedContentStatusFilteringService publishedContentStatusFilteringService)
{
_umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor));
_umbracoContextAccessor = umbracoContextAccessor;
_umbracoContextFactory = umbracoContextFactory;
_urlProviders = urlProviders;
_mediaUrlProviders = mediaUrlProviders;
_variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor));
_variationContextAccessor = variationContextAccessor;
_navigationQueryService = navigationQueryService;
_publishedContentStatusFilteringService = publishedContentStatusFilteringService;
Mode = routingSettings.Value.UrlProviderMode;
}

[Obsolete("Use the non-obsolete constructor. Scheduled for removal in V18.")]
public UrlProvider(
IUmbracoContextAccessor umbracoContextAccessor,
IOptions<WebRoutingSettings> routingSettings,
UrlProviderCollection urlProviders,
MediaUrlProviderCollection mediaUrlProviders,
IVariationContextAccessor variationContextAccessor,
IDocumentNavigationQueryService navigationQueryService,
IPublishedContentStatusFilteringService publishedContentStatusFilteringService)
: this(
umbracoContextAccessor,
StaticServiceProvider.Instance.GetRequiredService<IUmbracoContextFactory>(),
routingSettings,
urlProviders,
mediaUrlProviders,
variationContextAccessor,
StaticServiceProvider.Instance.GetRequiredService<IPublishedContentCache>(),
navigationQueryService,
StaticServiceProvider.Instance.GetRequiredService<IPublishStatusQueryService>(),
publishedContentStatusFilteringService)
{
}

Check notice on line 80 in src/Umbraco.Core/Routing/UrlProvider.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

✅ Getting better: Constructor Over-Injection

UrlProvider decreases from 9 to 7 arguments, max arguments = 5. This constructor has too many arguments, indicating an object with low cohesion or missing function argument abstraction. Avoid adding more arguments.

[Obsolete("Use the non-obsolete constructor. Scheduled for removal in V17.")]
public UrlProvider(
IUmbracoContextAccessor umbracoContextAccessor,
Expand Down Expand Up @@ -126,35 +160,28 @@
{
}

private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IEnumerable<IUrlProvider> _urlProviders;
private readonly IEnumerable<IMediaUrlProvider> _mediaUrlProviders;
private readonly IVariationContextAccessor _variationContextAccessor;
private readonly IDocumentNavigationQueryService _navigationQueryService;
private readonly IPublishedContentStatusFilteringService _publishedContentStatusFilteringService;

/// <summary>
/// Gets or sets the provider URL mode.
/// </summary>
public UrlMode Mode { get; set; }

#endregion

#region GetUrl

private IPublishedContent? GetDocument(int id)
{
IUmbracoContext umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();
IUmbracoContext umbracoContext = GetRequiredUmbracoContext();
return umbracoContext.Content?.GetById(id);
}

private IPublishedContent? GetDocument(Guid id)
{
IUmbracoContext umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();
IUmbracoContext umbracoContext = GetRequiredUmbracoContext();
return umbracoContext.Content?.GetById(id);
}

private IPublishedContent? GetMedia(Guid id)
{
IUmbracoContext umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();
IUmbracoContext umbracoContext = GetRequiredUmbracoContext();
return umbracoContext.Media?.GetById(id);
}

Expand Down Expand Up @@ -217,7 +244,7 @@

if (current == null)
{
IUmbracoContext umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();
IUmbracoContext umbracoContext = GetRequiredUmbracoContext();
current = umbracoContext.CleanedUmbracoUrl;
}

Expand All @@ -229,7 +256,7 @@

public string GetUrlFromRoute(int id, string? route, string? culture)
{
IUmbracoContext umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();
IUmbracoContext umbracoContext = GetRequiredUmbracoContext();
NewDefaultUrlProvider? provider = _urlProviders.OfType<NewDefaultUrlProvider>().FirstOrDefault();
var url = provider == null
? route // what else?
Expand All @@ -253,7 +280,7 @@
/// </remarks>
public IEnumerable<UrlInfo> GetOtherUrls(int id)
{
IUmbracoContext umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();
IUmbracoContext umbracoContext = GetRequiredUmbracoContext();
return GetOtherUrls(id, umbracoContext.CleanedUmbracoUrl);
}

Expand Down Expand Up @@ -333,7 +360,7 @@

if (current == null)
{
IUmbracoContext umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();
IUmbracoContext umbracoContext = GetRequiredUmbracoContext();
current = umbracoContext.CleanedUmbracoUrl;
}

Expand All @@ -346,5 +373,16 @@
}

#endregion

private IUmbracoContext GetRequiredUmbracoContext()
{
if (_umbracoContextAccessor.TryGetUmbracoContext(out IUmbracoContext? umbracoContext))
{
return umbracoContext;
}

using UmbracoContextReference ctx = _umbracoContextFactory.EnsureUmbracoContext();
return ctx.UmbracoContext;
}
}
}
2 changes: 1 addition & 1 deletion src/Umbraco.Core/Services/ContentPublishingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@
return MapInternalPublishingAttempt(minimalAttempt);
}

_logger.LogInformation("Starting async background thread for publishing branch.");
_logger.LogDebug("Starting long running operation for publishing branch {Key} on background thread.", key);
Attempt<Guid, LongRunningOperationEnqueueStatus> enqueueAttempt = await _longRunningOperationService.RunAsync(
PublishBranchOperationType,
async _ => await PerformPublishBranchAsync(key, cultures, publishBranchFilter, userKey, returnContent: false),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.

using System.Text.Json;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Models.DeliveryApi;
using Umbraco.Cms.Core.Models.PublishedContent;
Expand Down Expand Up @@ -53,10 +54,10 @@ public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType
{
value = _jsonSerializer.Deserialize<ImageCropperValue>(sourceString);
}
catch (Exception ex)
catch (JsonException ex)
{
// cannot deserialize, assume it may be a raw image URL
_logger.LogError(ex, "Could not deserialize string '{JsonString}' into an image cropper value.", sourceString);
// Cannot deserialize, assume it may be a raw image URL.
_logger.LogDebug(ex, "Could not deserialize string '{JsonString}' into an image cropper value.", sourceString);
value = new ImageCropperValue { Src = sourceString };
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Cms.Core.Templates;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Tests.Common;
using Umbraco.Cms.Tests.UnitTests.TestHelpers.Objects;

Expand Down Expand Up @@ -108,11 +109,14 @@ public void Ensure_Image_Sources()
var webRoutingSettings = new WebRoutingSettings();
var publishedUrlProvider = new UrlProvider(
umbracoContextAccessor,
Mock.Of<IUmbracoContextFactory>(),
Options.Create(webRoutingSettings),
new UrlProviderCollection(() => Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(() => new[] { mediaUrlProvider.Object }),
Mock.Of<IVariationContextAccessor>(),
Mock.Of<IPublishedContentCache>(),
Mock.Of<IDocumentNavigationQueryService>(),
Mock.Of<IPublishStatusQueryService>(),
Mock.Of<IPublishedContentStatusFilteringService>());

using (var reference = umbracoContextFactory.EnsureUmbracoContext())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Cms.Core.Templates;
Expand Down Expand Up @@ -450,11 +451,14 @@ private static UrlProvider CreatePublishedUrlProvider(

return new UrlProvider(
umbracoContextAccessor,
Mock.Of<IUmbracoContextFactory>(),
Options.Create(new WebRoutingSettings()),
new UrlProviderCollection(() => new[] { contentUrlProvider.Object }),
new MediaUrlProviderCollection(() => new[] { mediaUrlProvider.Object }),
Mock.Of<IVariationContextAccessor>(),
Mock.Of<IPublishedContentCache>(),
navigationQueryService.Object,
Mock.Of<IPublishStatusQueryService>(),
new Mock<IPublishedContentStatusFilteringService>().Object);
}
}