Add media url provider support

This commit is contained in:
Rasmus John Pedersen
2019-04-15 15:57:35 +02:00
parent 9f9d24e6b3
commit d0701ae34e
28 changed files with 322 additions and 58 deletions

View File

@@ -159,6 +159,7 @@ namespace Umbraco.Tests.Cache
TestObjects.GetUmbracoSettings(),
TestObjects.GetGlobalSettings(),
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
// just assert it does not throw

View File

@@ -81,6 +81,7 @@ namespace Umbraco.Tests.Cache.PublishedCache
new WebSecurity(_httpContextFactory.HttpContext, Current.Services.UserService, globalSettings),
umbracoSettings,
Enumerable.Empty<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
globalSettings,
new TestVariationContextAccessor());

View File

@@ -71,6 +71,7 @@ namespace Umbraco.Tests.PublishedContent
new WebSecurity(httpContext, Current.Services.UserService, globalSettings),
TestObjects.GetUmbracoSettings(),
Enumerable.Empty<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
globalSettings,
new TestVariationContextAccessor());

View File

@@ -118,6 +118,7 @@ namespace Umbraco.Tests.Scoping
new WebSecurity(httpContext, Current.Services.UserService, globalSettings),
umbracoSettings ?? SettingsForTests.GetDefaultUmbracoSettings(),
urlProviders ?? Enumerable.Empty<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
globalSettings,
new TestVariationContextAccessor());

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using Microsoft.Owin;
using Moq;
@@ -33,7 +34,7 @@ namespace Umbraco.Tests.Security
Mock.Of<HttpContextBase>(),
Mock.Of<IPublishedSnapshotService>(),
new WebSecurity(Mock.Of<HttpContextBase>(), Current.Services.UserService, globalSettings),
TestObjects.GetUmbracoSettings(), new List<IUrlProvider>(),globalSettings,
TestObjects.GetUmbracoSettings(), new List<IUrlProvider>(), Enumerable.Empty<IMediaUrlProvider>(), globalSettings,
new TestVariationContextAccessor());
var runtime = Mock.Of<IRuntimeState>(x => x.Level == RuntimeLevel.Install);
@@ -53,7 +54,7 @@ namespace Umbraco.Tests.Security
Mock.Of<HttpContextBase>(),
Mock.Of<IPublishedSnapshotService>(),
new WebSecurity(Mock.Of<HttpContextBase>(), Current.Services.UserService, globalSettings),
TestObjects.GetUmbracoSettings(), new List<IUrlProvider>(), globalSettings,
TestObjects.GetUmbracoSettings(), new List<IUrlProvider>(), Enumerable.Empty<IMediaUrlProvider>(), globalSettings,
new TestVariationContextAccessor());
var runtime = Mock.Of<IRuntimeState>(x => x.Level == RuntimeLevel.Run);

View File

@@ -139,6 +139,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
webSecurity.Object,
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
Enumerable.Empty<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
globalSettings,
new TestVariationContextAccessor());

View File

@@ -122,6 +122,7 @@ namespace Umbraco.Tests.TestHelpers
var umbracoSettings = GetUmbracoSettings();
var globalSettings = GetGlobalSettings();
var urlProviders = new UrlProviderCollection(Enumerable.Empty<IUrlProvider>());
var mediaUrlProviders = new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>());
if (accessor == null) accessor = new TestUmbracoContextAccessor();
@@ -133,6 +134,7 @@ namespace Umbraco.Tests.TestHelpers
umbracoSettings,
globalSettings,
urlProviders,
mediaUrlProviders,
Mock.Of<IUserService>());
return umbracoContextFactory.EnsureUmbracoContext(httpContext).UmbracoContext;

View File

@@ -380,6 +380,7 @@ namespace Umbraco.Tests.TestHelpers
Factory.GetInstance<IGlobalSettings>()),
umbracoSettings ?? Factory.GetInstance<IUmbracoSettingsSection>(),
urlProviders ?? Enumerable.Empty<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
globalSettings ?? Factory.GetInstance<IGlobalSettings>(),
new TestVariationContextAccessor());

View File

@@ -80,7 +80,7 @@ namespace Umbraco.Tests.Testing.TestingTests
.Returns(UrlInfo.Url("/hello/world/1234"));
var urlProvider = urlProviderMock.Object;
var theUrlProvider = new UrlProvider(umbracoContext, new [] { urlProvider }, umbracoContext.VariationContextAccessor);
var theUrlProvider = new UrlProvider(umbracoContext, new [] { urlProvider }, Enumerable.Empty<IMediaUrlProvider>(), umbracoContext.VariationContextAccessor);
var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty<string>(), Enumerable.Empty<PublishedPropertyType>(), ContentVariation.Nothing);
var publishedContent = Mock.Of<IPublishedContent>();

View File

@@ -72,6 +72,7 @@ namespace Umbraco.Tests.Web.Mvc
TestObjects.GetUmbracoSettings(),
globalSettings,
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -101,6 +102,7 @@ namespace Umbraco.Tests.Web.Mvc
TestObjects.GetUmbracoSettings(),
globalSettings,
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -130,6 +132,7 @@ namespace Umbraco.Tests.Web.Mvc
TestObjects.GetUmbracoSettings(),
globalSettings,
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -159,6 +162,7 @@ namespace Umbraco.Tests.Web.Mvc
TestObjects.GetUmbracoSettings(),
globalSettings,
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());

View File

@@ -47,6 +47,7 @@ namespace Umbraco.Tests.Web.Mvc
TestObjects.GetUmbracoSettings(),
globalSettings,
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -74,6 +75,7 @@ namespace Umbraco.Tests.Web.Mvc
TestObjects.GetUmbracoSettings(),
globalSettings,
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -104,6 +106,7 @@ namespace Umbraco.Tests.Web.Mvc
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
globalSettings,
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -141,6 +144,7 @@ namespace Umbraco.Tests.Web.Mvc
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == webRoutingSettings),
globalSettings,
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());

View File

@@ -440,6 +440,7 @@ namespace Umbraco.Tests.Web.Mvc
new WebSecurity(http, Current.Services.UserService, globalSettings),
TestObjects.GetUmbracoSettings(),
Enumerable.Empty<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
globalSettings,
new TestVariationContextAccessor());

View File

@@ -105,6 +105,7 @@ namespace Umbraco.Tests.Web
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
globalSettings,
new UrlProviderCollection(new[] { testUrlProvider.Object }),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
using (var reference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>()))

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
@@ -31,6 +32,7 @@ namespace Umbraco.Tests.Web
new WebSecurity(Mock.Of<HttpContextBase>(), Current.Services.UserService, TestObjects.GetGlobalSettings()),
TestObjects.GetUmbracoSettings(),
new List<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
TestObjects.GetGlobalSettings(),
new TestVariationContextAccessor());
var r1 = new RouteData();
@@ -49,6 +51,7 @@ namespace Umbraco.Tests.Web
new WebSecurity(Mock.Of<HttpContextBase>(), Current.Services.UserService, TestObjects.GetGlobalSettings()),
TestObjects.GetUmbracoSettings(),
new List<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
TestObjects.GetGlobalSettings(),
new TestVariationContextAccessor());
@@ -77,6 +80,7 @@ namespace Umbraco.Tests.Web
new WebSecurity(Mock.Of<HttpContextBase>(), Current.Services.UserService, TestObjects.GetGlobalSettings()),
TestObjects.GetUmbracoSettings(),
new List<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
TestObjects.GetGlobalSettings(),
new TestVariationContextAccessor());

View File

@@ -101,6 +101,9 @@ namespace Umbraco.Web.Composing
public static UrlProviderCollection UrlProviders
=> Factory.GetInstance<UrlProviderCollection>();
public static MediaUrlProviderCollection MediaUrlProviders
=> Factory.GetInstance<MediaUrlProviderCollection>();
public static HealthCheckCollectionBuilder HealthCheckCollectionBuilder
=> Factory.GetInstance<HealthCheckCollectionBuilder>();

View File

@@ -90,6 +90,13 @@ namespace Umbraco.Web
public static UrlProviderCollectionBuilder UrlProviders(this Composition composition)
=> composition.WithCollectionBuilder<UrlProviderCollectionBuilder>();
/// <summary>
/// Gets the media url providers collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
public static MediaUrlProviderCollectionBuilder MediaUrlProviders(this Composition composition)
=> composition.WithCollectionBuilder<MediaUrlProviderCollectionBuilder>();
/// <summary>
/// Gets the backoffice sections/applications collection builder.
/// </summary>

View File

@@ -130,15 +130,15 @@ namespace Umbraco.Web
if (mediaItem.HasProperty(propertyAlias) == false || mediaItem.HasValue(propertyAlias) == false)
return string.Empty;
var mediaItemUrl = mediaItem.MediaUrl(propertyAlias);
//get the default obj from the value converter
var cropperValue = mediaItem.Value(propertyAlias);
//is it strongly typed?
var stronglyTyped = cropperValue as ImageCropperValue;
string mediaItemUrl;
if (stronglyTyped != null)
{
mediaItemUrl = stronglyTyped.Src;
return GetCropUrl(
mediaItemUrl, stronglyTyped, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions,
cacheBusterValue, furtherOptions, ratioMode, upScale);
@@ -149,14 +149,12 @@ namespace Umbraco.Web
if (jobj != null)
{
stronglyTyped = jobj.ToObject<ImageCropperValue>();
mediaItemUrl = stronglyTyped.Src;
return GetCropUrl(
mediaItemUrl, stronglyTyped, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions,
cacheBusterValue, furtherOptions, ratioMode, upScale);
}
//it's a single string
mediaItemUrl = cropperValue.ToString();
return GetCropUrl(
mediaItemUrl, width, height, mediaItemUrl, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions,
cacheBusterValue, furtherOptions, ratioMode, upScale);
@@ -322,7 +320,7 @@ namespace Umbraco.Web
if (crop == null && !string.IsNullOrWhiteSpace(cropAlias))
return null;
imageProcessorUrl.Append(cropDataSet.Src);
imageProcessorUrl.Append(imageUrl);
cropDataSet.AppendCropBaseUrl(imageProcessorUrl, crop, string.IsNullOrWhiteSpace(cropAlias), preferFocalPoint);
if (crop != null & useCropDimensions)

View File

@@ -81,54 +81,23 @@ namespace Umbraco.Web.Models
/// <inheritdoc />
/// <remarks>
/// The url of documents are computed by the document url providers. The url of medias are, at the moment,
/// computed here from the 'umbracoFile' property -- but we should move to media url providers at some point.
/// The url of documents are computed by the document url providers. The url of medias are computed by the media url providers
/// </remarks>
public virtual string GetUrl(string culture = null) // TODO: consider .GetCulture("fr-FR").Url
{
var umbracoContext = UmbracoContextAccessor.UmbracoContext;
if (umbracoContext == null)
throw new InvalidOperationException("Cannot compute Url for a content item when UmbracoContext is null.");
if (umbracoContext.UrlProvider == null)
throw new InvalidOperationException("Cannot compute Url for a content item when UmbracoContext.UrlProvider is null.");
switch (ItemType)
{
case PublishedItemType.Content:
var umbracoContext = UmbracoContextAccessor.UmbracoContext;
if (umbracoContext == null)
throw new InvalidOperationException("Cannot compute Url for a content item when UmbracoContext is null.");
if (umbracoContext.UrlProvider == null)
throw new InvalidOperationException("Cannot compute Url for a content item when UmbracoContext.UrlProvider is null.");
return umbracoContext.UrlProvider.GetUrl(this, culture);
case PublishedItemType.Media:
var prop = GetProperty(Constants.Conventions.Media.File);
if (prop?.GetValue() == null)
{
return string.Empty;
}
var propType = ContentType.GetPropertyType(Constants.Conventions.Media.File);
// TODO: consider implementing media url providers
// note: that one does not support variations
//This is a hack - since we now have 2 properties that support a URL: upload and cropper, we need to detect this since we always
// want to return the normal URL and the cropper stores data as json
switch (propType.EditorAlias)
{
case Constants.PropertyEditors.Aliases.UploadField:
return prop.GetValue().ToString();
case Constants.PropertyEditors.Aliases.ImageCropper:
//get the url from the json format
var stronglyTyped = prop.GetValue() as ImageCropperValue;
if (stronglyTyped != null)
{
return stronglyTyped.Src;
}
return prop.GetValue()?.ToString();
}
return string.Empty;
return umbracoContext.UrlProvider.GetMediaUrl(this, Constants.Conventions.Media.File, culture);
default:
throw new NotSupportedException();
}

View File

@@ -45,21 +45,58 @@ namespace Umbraco.Web
public static string UrlAbsolute(this IPublishedContent content)
{
// adapted from PublishedContentBase.Url
if (Current.UmbracoContext == null)
throw new InvalidOperationException("Cannot resolve a Url for a content item when Current.UmbracoContext is null.");
if (Current.UmbracoContext.UrlProvider == null)
throw new InvalidOperationException("Cannot resolve a Url for a content item when Current.UmbracoContext.UrlProvider is null.");
switch (content.ItemType)
{
case PublishedItemType.Content:
if (Current.UmbracoContext == null)
throw new InvalidOperationException("Cannot resolve a Url for a content item when Current.UmbracoContext is null.");
if (Current.UmbracoContext.UrlProvider == null)
throw new InvalidOperationException("Cannot resolve a Url for a content item when Current.UmbracoContext.UrlProvider is null.");
return Current.UmbracoContext.UrlProvider.GetUrl(content.Id, true);
case PublishedItemType.Media:
throw new NotSupportedException("AbsoluteUrl is not supported for media types.");
return Current.UmbracoContext.UrlProvider.GetMediaUrl(content, Constants.Conventions.Media.File, true);
default:
throw new ArgumentOutOfRangeException();
}
}
/// <summary>
/// Gets the url for the media.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="propertyAlias">The property alias to resolve the url from.</param>
/// <param name="culture">The variation language.</param>
/// <returns>The url for the content.</returns>
/// <remarks>Better use the <c>GetMediaUrl</c> method but that method is here to complement <c>MediaUrlAbsolute()</c>.</remarks>
public static string MediaUrl(this IPublishedContent content, string propertyAlias, string culture = null)
{
if (Current.UmbracoContext == null)
throw new InvalidOperationException("Cannot resolve a Url for a content item when Current.UmbracoContext is null.");
if (Current.UmbracoContext.UrlProvider == null)
throw new InvalidOperationException("Cannot resolve a Url for a content item when Current.UmbracoContext.UrlProvider is null.");
return Current.UmbracoContext.UrlProvider.GetMediaUrl(content, propertyAlias, culture);
}
/// <summary>
/// Gets the absolute url for the media.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="propertyAlias">The property alias to resolve the url from.</param>
/// <param name="culture">The variation language.</param>
/// <returns>The absolute url for the media.</returns>
public static string MediaUrlAbsolute(this IPublishedContent content, string propertyAlias, string culture = null)
{
if (Current.UmbracoContext == null)
throw new InvalidOperationException("Cannot resolve a Url for a content item when Current.UmbracoContext is null.");
if (Current.UmbracoContext.UrlProvider == null)
throw new InvalidOperationException("Cannot resolve a Url for a content item when Current.UmbracoContext.UrlProvider is null.");
return Current.UmbracoContext.UrlProvider.GetMediaUrl(content, propertyAlias, true, culture);
}
/// <summary>
/// Gets the Url segment.
/// </summary>

View File

@@ -0,0 +1,76 @@
using System;
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors.ValueConverters;
namespace Umbraco.Web.Routing
{
/// <summary>
/// Default media url provider.
/// </summary>
public class DefaultMediaUrlProvider : IMediaUrlProvider
{
/// <inheritdoc />
public virtual UrlInfo GetMediaUrl(UmbracoContext umbracoContext, IPublishedContent content,
string propertyAlias,
UrlProviderMode mode, string culture, Uri current)
{
var prop = content.GetProperty(propertyAlias);
var value = prop?.GetValue(culture);
if (value == null)
{
return null;
}
var propType = content.ContentType.GetPropertyType(propertyAlias);
string path = null;
switch (propType.EditorAlias)
{
case Constants.PropertyEditors.Aliases.UploadField:
path = value.ToString();
break;
case Constants.PropertyEditors.Aliases.ImageCropper:
//get the url from the json format
var stronglyTyped = value as ImageCropperValue;
if (stronglyTyped != null)
{
path = stronglyTyped.Src;
break;
}
path = value.ToString();
break;
}
return path == null ? null : UrlInfo.Url(AssembleUrl(path, current, mode).ToString(), culture);
}
private Uri AssembleUrl(string path, Uri current, UrlProviderMode mode)
{
if (string.IsNullOrEmpty(path))
return null;
Uri uri;
if (current == null)
mode = UrlProviderMode.Relative; // best we can do
switch (mode)
{
case UrlProviderMode.Absolute:
uri = new Uri(current?.GetLeftPart(UriPartial.Authority) + path);
break;
case UrlProviderMode.Relative:
case UrlProviderMode.Auto:
uri = new Uri(path, UriKind.Relative);
break;
default:
throw new ArgumentOutOfRangeException(nameof(mode));
}
return uri.Rewrite(UriUtility.ToAbsolute(uri.GetSafeAbsolutePath()));
}
}
}

View File

@@ -0,0 +1,31 @@
using System;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Routing
{
/// <summary>
/// Provides media urls.
/// </summary>
public interface IMediaUrlProvider
{
/// <summary>
/// Gets the nice url of a media item.
/// </summary>
/// <param name="umbracoContext">The Umbraco context.</param>
/// <param name="content">The published content.</param>
/// <param name="propertyAlias">The property alias to resolve the url from.</param>
/// <param name="mode">The url mode.</param>
/// <param name="culture">The variation language.</param>
/// <param name="current">The current absolute url.</param>
/// <returns>The url for the media.</returns>
/// <remarks>
/// <para>The url is absolute or relative depending on <c>mode</c> and on <c>current</c>.</para>
/// <para>If the media is multi-lingual, gets the url for the specified culture or,
/// when no culture is specified, the current culture.</para>
/// <para>The url provider can ignore the mode and always return an absolute url,
/// e.g. a cdn url provider will most likely always return an absolute url.</para>
/// <para>If the provider is unable to provide a url, it returns <c>null</c>.</para>
/// </remarks>
UrlInfo GetMediaUrl(UmbracoContext umbracoContext, IPublishedContent content, string propertyAlias, UrlProviderMode mode, string culture, Uri current);
}
}

View File

@@ -0,0 +1,13 @@
using System.Collections.Generic;
using Umbraco.Core.Composing;
namespace Umbraco.Web.Routing
{
public class MediaUrlProviderCollection : BuilderCollectionBase<IMediaUrlProvider>
{
public MediaUrlProviderCollection(IEnumerable<IMediaUrlProvider> items)
: base(items)
{
}
}
}

View File

@@ -0,0 +1,9 @@
using Umbraco.Core.Composing;
namespace Umbraco.Web.Routing
{
public class MediaUrlProviderCollectionBuilder : OrderedCollectionBuilderBase<MediaUrlProviderCollectionBuilder, MediaUrlProviderCollection, IMediaUrlProvider>
{
protected override MediaUrlProviderCollectionBuilder This => this;
}
}

View File

@@ -7,6 +7,7 @@ using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
using Umbraco.Web.Models;
namespace Umbraco.Web.Routing
{
@@ -23,13 +24,15 @@ namespace Umbraco.Web.Routing
/// <param name="umbracoContext">The Umbraco context.</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>
/// <param name="variationContextAccessor">The current variation accessor.</param>
public UrlProvider(UmbracoContext umbracoContext, IWebRoutingSection routingSettings, IEnumerable<IUrlProvider> urlProviders, IVariationContextAccessor variationContextAccessor)
public UrlProvider(UmbracoContext umbracoContext, IWebRoutingSection routingSettings, IEnumerable<IUrlProvider> urlProviders, IEnumerable<IMediaUrlProvider> mediaUrlProviders, IVariationContextAccessor variationContextAccessor)
{
if (routingSettings == null) throw new ArgumentNullException(nameof(routingSettings));
_umbracoContext = umbracoContext ?? throw new ArgumentNullException(nameof(umbracoContext));
_urlProviders = urlProviders;
_mediaUrlProviders = mediaUrlProviders;
_variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor));
var provider = UrlProviderMode.Auto;
Mode = provider;
@@ -45,12 +48,14 @@ namespace Umbraco.Web.Routing
/// </summary>
/// <param name="umbracoContext">The Umbraco context.</param>
/// <param name="urlProviders">The list of url providers.</param>
/// <param name="mediaUrlProviders">The list of media url providers</param>
/// <param name="variationContextAccessor">The current variation accessor.</param>
/// <param name="mode">An optional provider mode.</param>
public UrlProvider(UmbracoContext umbracoContext, IEnumerable<IUrlProvider> urlProviders, IVariationContextAccessor variationContextAccessor, UrlProviderMode mode = UrlProviderMode.Auto)
public UrlProvider(UmbracoContext umbracoContext, IEnumerable<IUrlProvider> urlProviders, IEnumerable<IMediaUrlProvider> mediaUrlProviders, IVariationContextAccessor variationContextAccessor, UrlProviderMode mode = UrlProviderMode.Auto)
{
_umbracoContext = umbracoContext ?? throw new ArgumentNullException(nameof(umbracoContext));
_urlProviders = urlProviders;
_mediaUrlProviders = mediaUrlProviders;
_variationContextAccessor = variationContextAccessor;
Mode = mode;
@@ -58,6 +63,7 @@ namespace Umbraco.Web.Routing
private readonly UmbracoContext _umbracoContext;
private readonly IEnumerable<IUrlProvider> _urlProviders;
private readonly IEnumerable<IMediaUrlProvider> _mediaUrlProviders;
private readonly IVariationContextAccessor _variationContextAccessor;
/// <summary>
@@ -250,5 +256,86 @@ namespace Umbraco.Web.Routing
}
#endregion
#region GetMediaUrl
/// <summary>
/// Gets the url of a media item.
/// </summary>
/// <param name="content">The published content.</param>
/// <param name="propertyAlias">The property alias to resolve the url from.</param>
/// <param name="culture">The variation language.</param>
/// <param name="current">The current absolute url.</param>
/// <returns>The url for the media.</returns>
/// <remarks>
/// <para>The url is absolute or relative depending on <c>mode</c> and on <c>current</c>.</para>
/// <para>If the media is multi-lingual, gets the url for the specified culture or,
/// when no culture is specified, the current culture.</para>
/// <para>If the provider is unable to provide a url, it returns <see cref="String.Empty"/>.</para>
/// </remarks>
public string GetMediaUrl(IPublishedContent content, string propertyAlias, string culture = null, Uri current = null)
=> GetMediaUrl(content, propertyAlias, Mode, culture, current);
/// <summary>
/// Gets the url of a media item.
/// </summary>
/// <param name="content">The published content.</param>
/// <param name="propertyAlias">The property alias to resolve the url from.</param>
/// <param name="absolute">A value indicating whether the url should be absolute in any case.</param>
/// <param name="culture">The variation language.</param>
/// <param name="current">The current absolute url.</param>
/// <returns>The url for the media.</returns>
/// <remarks>
/// <para>The url is absolute or relative depending on <c>mode</c> and on <c>current</c>.</para>
/// <para>If the media is multi-lingual, gets the url for the specified culture or,
/// when no culture is specified, the current culture.</para>
/// <para>If the provider is unable to provide a url, it returns <see cref="String.Empty"/>.</para>
/// </remarks>
public string GetMediaUrl(IPublishedContent content, string propertyAlias, bool absolute, string culture = null, Uri current = null)
=> GetMediaUrl(content, propertyAlias, GetMode(absolute), culture, current);
/// <summary>
/// Gets the url of a media item.
/// </summary>
/// <param name="content">The published content.</param>
/// <param name="propertyAlias">The property alias to resolve the url from.</param>
/// <param name="mode">The url mode.</param>
/// <param name="culture">The variation language.</param>
/// <param name="current">The current absolute url.</param>
/// <returns>The url for the media.</returns>
/// <remarks>
/// <para>The url is absolute or relative depending on <c>mode</c> and on <c>current</c>.</para>
/// <para>If the media is multi-lingual, gets the url for the specified culture or,
/// when no culture is specified, the current culture.</para>
/// <para>If the provider is unable to provide a url, it returns <see cref="String.Empty"/>.</para>
/// </remarks>
public string GetMediaUrl(IPublishedContent content,
string propertyAlias, UrlProviderMode mode,
string culture = null, Uri current = null)
{
if (propertyAlias == null) throw new ArgumentNullException(nameof(propertyAlias));
if (content == null)
return "";
// this the ONLY place where we deal with default culture - IMediaUrlProvider always receive a culture
// be nice with tests, assume things can be null, ultimately fall back to invariant
// (but only for variant content of course)
if (content.ContentType.VariesByCulture())
{
if (culture == null)
culture = _variationContextAccessor?.VariationContext?.Culture ?? "";
}
if (current == null)
current = _umbracoContext.CleanedUmbracoUrl;
var url = _mediaUrlProviders.Select(provider =>
provider.GetMediaUrl(_umbracoContext, content, propertyAlias, mode, culture, current))
.FirstOrDefault(u => u != null);
return url?.Text ?? "";
}
#endregion
}
}

View File

@@ -183,6 +183,9 @@ namespace Umbraco.Web.Runtime
.Append<AliasUrlProvider>()
.Append<DefaultUrlProvider>();
composition.WithCollectionBuilder<MediaUrlProviderCollectionBuilder>()
.Append<DefaultMediaUrlProvider>();
composition.RegisterUnique<IContentLastChanceFinder, ContentFinderByConfigured404>();
composition.WithCollectionBuilder<ContentFinderCollectionBuilder>()

View File

@@ -214,7 +214,11 @@
<Compile Include="PublishedCache\NuCache\Snap\GenObj.cs" />
<Compile Include="PublishedCache\NuCache\Snap\GenRef.cs" />
<Compile Include="PublishedCache\NuCache\Snap\LinkedNode.cs" />
<Compile Include="Routing\DefaultMediaUrlProvider.cs" />
<Compile Include="Routing\IMediaUrlProvider.cs" />
<Compile Include="Routing\IPublishedRouter.cs" />
<Compile Include="Routing\MediaUrlProviderCollection.cs" />
<Compile Include="Routing\MediaUrlProviderCollectionBuilder.cs" />
<Compile Include="Services\DashboardService.cs" />
<Compile Include="Services\IDashboardService.cs" />
<Compile Include="Models\Link.cs" />

View File

@@ -33,6 +33,7 @@ namespace Umbraco.Web
WebSecurity webSecurity,
IUmbracoSettingsSection umbracoSettings,
IEnumerable<IUrlProvider> urlProviders,
IEnumerable<IMediaUrlProvider> mediaUrlProviders,
IGlobalSettings globalSettings,
IVariationContextAccessor variationContextAccessor)
{
@@ -41,6 +42,7 @@ namespace Umbraco.Web
if (webSecurity == null) throw new ArgumentNullException(nameof(webSecurity));
if (umbracoSettings == null) throw new ArgumentNullException(nameof(umbracoSettings));
if (urlProviders == null) throw new ArgumentNullException(nameof(urlProviders));
if (mediaUrlProviders == null) throw new ArgumentNullException(nameof(mediaUrlProviders));
VariationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor));
_globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings));
@@ -71,7 +73,7 @@ namespace Umbraco.Web
//
OriginalRequestUrl = GetRequestFromContext()?.Url ?? new Uri("http://localhost");
CleanedUmbracoUrl = UriUtility.UriToUmbraco(OriginalRequestUrl);
UrlProvider = new UrlProvider(this, umbracoSettings.WebRouting, urlProviders, variationContextAccessor);
UrlProvider = new UrlProvider(this, umbracoSettings.WebRouting, urlProviders, mediaUrlProviders, variationContextAccessor);
}
/// <summary>

View File

@@ -29,12 +29,13 @@ namespace Umbraco.Web
private readonly IUmbracoSettingsSection _umbracoSettings;
private readonly IGlobalSettings _globalSettings;
private readonly UrlProviderCollection _urlProviders;
private readonly MediaUrlProviderCollection _mediaUrlProviders;
private readonly IUserService _userService;
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoContextFactory"/> class.
/// </summary>
public UmbracoContextFactory(IUmbracoContextAccessor umbracoContextAccessor, IPublishedSnapshotService publishedSnapshotService, IVariationContextAccessor variationContextAccessor, IDefaultCultureAccessor defaultCultureAccessor, IUmbracoSettingsSection umbracoSettings, IGlobalSettings globalSettings, UrlProviderCollection urlProviders, IUserService userService)
public UmbracoContextFactory(IUmbracoContextAccessor umbracoContextAccessor, IPublishedSnapshotService publishedSnapshotService, IVariationContextAccessor variationContextAccessor, IDefaultCultureAccessor defaultCultureAccessor, IUmbracoSettingsSection umbracoSettings, IGlobalSettings globalSettings, UrlProviderCollection urlProviders, MediaUrlProviderCollection mediaUrlProviders, IUserService userService)
{
_umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor));
_publishedSnapshotService = publishedSnapshotService ?? throw new ArgumentNullException(nameof(publishedSnapshotService));
@@ -44,6 +45,7 @@ namespace Umbraco.Web
_umbracoSettings = umbracoSettings ?? throw new ArgumentNullException(nameof(umbracoSettings));
_globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings));
_urlProviders = urlProviders ?? throw new ArgumentNullException(nameof(urlProviders));
_mediaUrlProviders = mediaUrlProviders ?? throw new ArgumentNullException(nameof(mediaUrlProviders));
_userService = userService ?? throw new ArgumentNullException(nameof(userService));
}
@@ -55,7 +57,7 @@ namespace Umbraco.Web
var webSecurity = new WebSecurity(httpContext, _userService, _globalSettings);
return new UmbracoContext(httpContext, _publishedSnapshotService, webSecurity, _umbracoSettings, _urlProviders, _globalSettings, _variationContextAccessor);
return new UmbracoContext(httpContext, _publishedSnapshotService, webSecurity, _umbracoSettings, _urlProviders, _mediaUrlProviders, _globalSettings, _variationContextAccessor);
}
/// <inheritdoc />