Fix Deserialization of defaultConfig from package.manifest

This commit is contained in:
Bjarke Berg
2021-03-10 21:13:13 +01:00
parent 88e92a0360
commit 78d8f0bacf
5 changed files with 236 additions and 1 deletions

View File

@@ -0,0 +1,25 @@
using System;
using System.ComponentModel;
namespace Umbraco.Cms.Web.Common.DependencyInjection
{
/// <summary>
/// INTERNAL Service locator. Should only be used if no other ways exist.
/// </summary>
/// <remarks>
/// It is created with only two goals in mind
/// 1) Continue to have the same extension methods on IPublishedContent and IPublishedElement as in V8. To make migration easier.
/// 2) To have a tool to avoid breaking changes in minor versions. All methods using this should in theory be obsolete.
///
/// Keep in mind, everything this is used, the code becomes basically untestable.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
internal static class StaticServiceProvider
{
/// <summary>
/// The service locator.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
internal static IServiceProvider Instance { get; set; }
}
}

View File

@@ -19,6 +19,7 @@ namespace Umbraco.Cms.Web.Common.DependencyInjection
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next) =>
app =>
{
StaticServiceProvider.Instance = app.ApplicationServices;
_options.Value.PreUmbracoPipeline(app);
app.UseUmbraco();

View File

@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using Examine;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Web.Common.DependencyInjection;
using Umbraco.Extensions;
namespace Umbraco.FriendlyExtensions
{
public static class FriendlyPublishedContentExtensions
{
private static IVariationContextAccessor VariationContextAccessor { get; } =
StaticServiceProvider.Instance.GetRequiredService<IVariationContextAccessor>();
private static IPublishedModelFactory PublishedModelFactory { get; } =
StaticServiceProvider.Instance.GetRequiredService<IPublishedModelFactory>();
private static IPublishedUrlProvider PublishedUrlProvider { get; } =
StaticServiceProvider.Instance.GetRequiredService<IPublishedUrlProvider>();
private static IUserService UserService { get; } =
StaticServiceProvider.Instance.GetRequiredService<IUserService>();
private static IUmbracoContextAccessor UmbracoContextAccessor { get; } =
StaticServiceProvider.Instance.GetRequiredService<IUmbracoContextAccessor>();
private static ISiteDomainHelper SiteDomainHelper { get; } =
StaticServiceProvider.Instance.GetRequiredService<ISiteDomainHelper>();
private static IExamineManager ExamineManager { get; } =
StaticServiceProvider.Instance.GetRequiredService<IExamineManager>();
/// <summary>
/// Creates a strongly typed published content model for an internal published content.
/// </summary>
/// <param name="content">The internal published content.</param>
/// <returns>The strongly typed published content model.</returns>
public static IPublishedContent CreateModel(
this IPublishedContent content)
=> content.CreateModel(PublishedModelFactory);
/// <summary>
/// Gets the name of the content item.
/// </summary>
/// <param name="content">The content item.</param>
/// <param name="culture">The specific culture to get the name for. If null is used the current culture is used (Default is null).</param>
public static string Name(
this IPublishedContent content,
string culture = null)
=> content.Name(VariationContextAccessor, culture);
/// <summary>
/// Gets the URL segment of the content item.
/// </summary>
/// <param name="content">The content item.</param>
/// <param name="culture">The specific culture to get the URL segment for. If null is used the current culture is used (Default is null).</param>
public static string UrlSegment(
this IPublishedContent content,
string culture = null)
=> content.UrlSegment(VariationContextAccessor, culture);
/// <summary>
/// Gets the url for a media.
/// </summary>
/// <param name="content">The content item.</param>
/// <param name="culture">The culture (use current culture by default).</param>
/// <param name="mode">The url mode (use site configuration by default).</param>
/// <param name="propertyAlias">The alias of the property (use 'umbracoFile' by default).</param>
/// <returns>The url for the media.</returns>
/// <remarks>
/// <para>The value of this property is contextual. It depends on the 'current' request uri,
/// if any. In addition, when the content type is multi-lingual, this is the url for the
/// specified culture. Otherwise, it is the invariant url.</para>
/// </remarks>
public static string MediaUrl(
this IPublishedContent content,
string culture = null,
UrlMode mode = UrlMode.Default,
string propertyAlias = Constants.Conventions.Media.File)
=> content.MediaUrl(PublishedUrlProvider, culture, mode, propertyAlias);
/// <summary>
/// Gets the name of the content item creator.
/// </summary>
/// <param name="content">The content item.</param>
public static string CreatorName(this IPublishedContent content) =>
content.CreatorName(UserService);
/// <summary>
/// Gets the name of the content item writer.
/// </summary>
/// <param name="content">The content item.</param>
public static string WriterName(this IPublishedContent content) =>
content.WriterName(UserService);
/// <summary>
/// Gets the culture assigned to a document by domains, in the context of a current Uri.
/// </summary>
/// <param name="content">The document.</param>
/// <param name="current">An optional current Uri.</param>
/// <returns>The culture assigned to the document by domains.</returns>
/// <remarks>
/// <para>In 1:1 multilingual setup, a document contains several cultures (there is not
/// one document per culture), and domains, withing the context of a current Uri, assign
/// a culture to that document.</para>
/// </remarks>
public static string GetCultureFromDomains(
this IPublishedContent content,
Uri current = null)
=> content.GetCultureFromDomains(UmbracoContextAccessor, SiteDomainHelper, current);
public static IEnumerable<PublishedSearchResult> SearchDescendants(
this IPublishedContent content,
string term,
string indexName = null)
=> content.SearchDescendants(ExamineManager, UmbracoContextAccessor, term, indexName);
public static IEnumerable<PublishedSearchResult> SearchChildren(
this IPublishedContent content,
string term,
string indexName = null)
=> content.SearchChildren(ExamineManager, UmbracoContextAccessor, term, indexName);
}
}

View File

@@ -0,0 +1,75 @@
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Web.Common.DependencyInjection;
using Umbraco.Extensions;
namespace Umbraco.FriendlyExtensions
{
public static class FriendlyPublishedElementExtensions
{
private static IPublishedValueFallback PublishedValueFallback { get; } =
StaticServiceProvider.Instance.GetRequiredService<IPublishedValueFallback>();
/// <summary>
/// Gets the value of a content's property identified by its alias.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="alias">The property alias.</param>
/// <param name="culture">The variation language.</param>
/// <param name="segment">The variation segment.</param>
/// <param name="fallback">Optional fallback strategy.</param>
/// <param name="defaultValue">The default value.</param>
/// <returns>The value of the content's property identified by the alias, if it exists, otherwise a default value.</returns>
/// <remarks>
/// <para>The value comes from <c>IPublishedProperty</c> field <c>Value</c> ie it is suitable for use when rendering content.</para>
/// <para>If no property with the specified alias exists, or if the property has no value, returns <paramref name="defaultValue"/>.</para>
/// <para>If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter.</para>
/// <para>The alias is case-insensitive.</para>
/// </remarks>
public static object Value(
this IPublishedElement content,
string alias,
string culture = null,
string segment = null,
Fallback fallback = default,
object defaultValue = default)
=> content.Value(PublishedValueFallback, alias, culture, segment, fallback, defaultValue);
/// <summary>
/// Gets the value of a content's property identified by its alias, converted to a specified type.
/// </summary>
/// <typeparam name="T">The target property type.</typeparam>
/// <param name="content">The content.</param>
/// <param name="alias">The property alias.</param>
/// <param name="culture">The variation language.</param>
/// <param name="segment">The variation segment.</param>
/// <param name="fallback">Optional fallback strategy.</param>
/// <param name="defaultValue">The default value.</param>
/// <returns>The value of the content's property identified by the alias, converted to the specified type.</returns>
/// <remarks>
/// <para>The value comes from <c>IPublishedProperty</c> field <c>Value</c> ie it is suitable for use when rendering content.</para>
/// <para>If no property with the specified alias exists, or if the property has no value, or if it could not be converted, returns <c>default(T)</c>.</para>
/// <para>If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter.</para>
/// <para>The alias is case-insensitive.</para>
/// </remarks>
public static T Value<T>(
this IPublishedElement content,
string alias,
string culture = null,
string segment = null,
Fallback fallback = default,
T defaultValue = default)
=> content.Value<T>(PublishedValueFallback, alias, culture, segment, fallback, defaultValue);
/// <summary>
/// Gets a value indicating whether the content is visible.
/// </summary>
/// <param name="content">The content.</param>
/// <returns>A value indicating whether the content is visible.</returns>
/// <remarks>A content is not visible if it has an umbracoNaviHide property with a value of "1". Otherwise,
/// the content is visible.</remarks>
public static bool IsVisible(this IPublishedElement content) => content.IsVisible(PublishedValueFallback);
}
}

View File

@@ -0,0 +1,221 @@
using System;
using System.Collections.Generic;
using System.Web;
using Examine;
using Microsoft.AspNetCore.Html;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.Examine;
namespace Umbraco.Extensions
{
public static class PublishedContentExtensions
{
#region Creator/Writer Names
/// <summary>
/// Gets the name of the content item creator.
/// </summary>
/// <param name="content">The content item.</param>
/// <param name="userService"></param>
public static string CreatorName(this IPublishedContent content, IUserService userService) => userService.GetProfileById(content.CreatorId)?.Name;
/// <summary>
/// Gets the name of the content item writer.
/// </summary>
/// <param name="content">The content item.</param>
/// <param name="userService"></param>
public static string WriterName(this IPublishedContent content, IUserService userService) => userService.GetProfileById(content.WriterId)?.Name;
#endregion
#region Variations
/// <summary>
/// Gets the culture assigned to a document by domains, in the context of a current Uri.
/// </summary>
/// <param name="content">The document.</param>
/// <param name="umbracoContextAccessor"></param>
/// <param name="siteDomainHelper"></param>
/// <param name="current">An optional current Uri.</param>
/// <returns>The culture assigned to the document by domains.</returns>
/// <remarks>
/// <para>In 1:1 multilingual setup, a document contains several cultures (there is not
/// one document per culture), and domains, withing the context of a current Uri, assign
/// a culture to that document.</para>
/// </remarks>
public static string GetCultureFromDomains(this IPublishedContent content, IUmbracoContextAccessor umbracoContextAccessor, ISiteDomainHelper siteDomainHelper, Uri current = null)
=> DomainUtilities.GetCultureFromDomains(content.Id, content.Path, current, umbracoContextAccessor.UmbracoContext, siteDomainHelper);
#endregion
#region Search
public static IEnumerable<PublishedSearchResult> SearchDescendants(this IPublishedContent content, IExamineManager examineManager, IUmbracoContextAccessor umbracoContextAccessor, string term, string indexName = null)
{
indexName = string.IsNullOrEmpty(indexName) ? Constants.UmbracoIndexes.ExternalIndexName : indexName;
if (!examineManager.TryGetIndex(indexName, out var index))
{
throw new InvalidOperationException("No index found with name " + indexName);
}
var searcher = index.GetSearcher();
//var t = term.Escape().Value;
//var luceneQuery = "+__Path:(" + content.Path.Replace("-", "\\-") + "*) +" + t;
var query = searcher.CreateQuery()
.Field(UmbracoExamineFieldNames.IndexPathFieldName, (content.Path + ",").MultipleCharacterWildcard())
.And()
.ManagedQuery(term);
return query.Execute().ToPublishedSearchResults(umbracoContextAccessor.UmbracoContext.Content);
}
public static IEnumerable<PublishedSearchResult> SearchChildren(this IPublishedContent content, IExamineManager examineManager, IUmbracoContextAccessor umbracoContextAccessor, string term, string indexName = null)
{
indexName = string.IsNullOrEmpty(indexName) ? Constants.UmbracoIndexes.ExternalIndexName : indexName;
if (!examineManager.TryGetIndex(indexName, out var index))
{
throw new InvalidOperationException("No index found with name " + indexName);
}
var searcher = index.GetSearcher();
//var t = term.Escape().Value;
//var luceneQuery = "+parentID:" + content.Id + " +" + t;
var query = searcher.CreateQuery()
.Field("parentID", content.Id)
.And()
.ManagedQuery(term);
return query.Execute().ToPublishedSearchResults(umbracoContextAccessor.UmbracoContext.Content);
}
#endregion
#region IsSomething: equality
/// <summary>
/// If the specified <paramref name="content" /> is equal to <paramref name="other" />, the HTML encoded <paramref name="valueIfTrue" /> will be returned; otherwise, <see cref="string.Empty" />.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="other">The other content.</param>
/// <param name="valueIfTrue">The value if <c>true</c>.</param>
/// <returns>
/// The HTML encoded value.
/// </returns>
public static IHtmlContent IsEqual(this IPublishedContent content, IPublishedContent other, string valueIfTrue) => content.IsEqual(other, valueIfTrue, string.Empty);
/// <summary>
/// If the specified <paramref name="content" /> is equal to <paramref name="other" />, the HTML encoded <paramref name="valueIfTrue" /> will be returned; otherwise, <paramref name="valueIfFalse" />.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="other">The other content.</param>
/// <param name="valueIfTrue">The value if <c>true</c>.</param>
/// <param name="valueIfFalse">The value if <c>false</c>.</param>
/// <returns>
/// The HTML encoded value.
/// </returns>
public static IHtmlContent IsEqual(this IPublishedContent content, IPublishedContent other, string valueIfTrue, string valueIfFalse) => new HtmlString(HttpUtility.HtmlEncode(content.IsEqual(other) ? valueIfTrue : valueIfFalse));
/// <summary>
/// If the specified <paramref name="content" /> is not equal to <paramref name="other" />, the HTML encoded <paramref name="valueIfTrue" /> will be returned; otherwise, <see cref="string.Empty" />.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="other">The other content.</param>
/// <param name="valueIfTrue">The value if <c>true</c>.</param>
/// <returns>
/// The HTML encoded value.
/// </returns>
public static IHtmlContent IsNotEqual(this IPublishedContent content, IPublishedContent other, string valueIfTrue) => content.IsNotEqual(other, valueIfTrue, string.Empty);
/// <summary>
/// If the specified <paramref name="content" /> is not equal to <paramref name="other" />, the HTML encoded <paramref name="valueIfTrue" /> will be returned; otherwise, <paramref name="valueIfFalse" />.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="other">The other content.</param>
/// <param name="valueIfTrue">The value if <c>true</c>.</param>
/// <param name="valueIfFalse">The value if <c>false</c>.</param>
/// <returns>
/// The HTML encoded value.
/// </returns>
public static IHtmlContent IsNotEqual(this IPublishedContent content, IPublishedContent other, string valueIfTrue, string valueIfFalse) => new HtmlString(HttpUtility.HtmlEncode(content.IsNotEqual(other) ? valueIfTrue : valueIfFalse));
#endregion
#region IsSomething: ancestors and descendants
/// <summary>
/// If the specified <paramref name="content" /> is a decendant of <paramref name="other" />, the HTML encoded <paramref name="valueIfTrue" /> will be returned; otherwise, <see cref="string.Empty" />.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="other">The other content.</param>
/// <param name="valueIfTrue">The value if <c>true</c>.</param>
/// <returns>
/// The HTML encoded value.
/// </returns>
public static IHtmlContent IsDescendant(this IPublishedContent content, IPublishedContent other, string valueIfTrue) => content.IsDescendant(other, valueIfTrue, string.Empty);
/// <summary>
/// If the specified <paramref name="content" /> is a decendant of <paramref name="other" />, the HTML encoded <paramref name="valueIfTrue" /> will be returned; otherwise, <paramref name="valueIfFalse" />.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="other">The other content.</param>
/// <param name="valueIfTrue">The value if <c>true</c>.</param>
/// <param name="valueIfFalse">The value if <c>false</c>.</param>
/// <returns>
/// The HTML encoded value.
/// </returns>
public static IHtmlContent IsDescendant(this IPublishedContent content, IPublishedContent other, string valueIfTrue, string valueIfFalse) => new HtmlString(HttpUtility.HtmlEncode(content.IsDescendant(other) ? valueIfTrue : valueIfFalse));
public static IHtmlContent IsDescendantOrSelf(this IPublishedContent content, IPublishedContent other, string valueIfTrue) => content.IsDescendantOrSelf(other, valueIfTrue, string.Empty);
/// <summary>
/// If the specified <paramref name="content" /> is a decendant of <paramref name="other" /> or are the same, the HTML encoded <paramref name="valueIfTrue" /> will be returned; otherwise, <paramref name="valueIfFalse" />.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="other">The other content.</param>
/// <param name="valueIfTrue">The value if <c>true</c>.</param>
/// <param name="valueIfFalse">The value if <c>false</c>.</param>
/// <returns>
/// The HTML encoded value.
/// </returns>
public static IHtmlContent IsDescendantOrSelf(this IPublishedContent content, IPublishedContent other, string valueIfTrue, string valueIfFalse) => new HtmlString(HttpUtility.HtmlEncode(content.IsDescendantOrSelf(other) ? valueIfTrue : valueIfFalse));
public static IHtmlContent IsAncestor(this IPublishedContent content, IPublishedContent other, string valueIfTrue) => content.IsAncestor(other, valueIfTrue, string.Empty);
/// <summary>
/// If the specified <paramref name="content" /> is an ancestor of <paramref name="other" />, the HTML encoded <paramref name="valueIfTrue" /> will be returned; otherwise, <paramref name="valueIfFalse" />.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="other">The other content.</param>
/// <param name="valueIfTrue">The value if <c>true</c>.</param>
/// <param name="valueIfFalse">The value if <c>false</c>.</param>
/// <returns>
/// The HTML encoded value.
/// </returns>
public static IHtmlContent IsAncestor(this IPublishedContent content, IPublishedContent other, string valueIfTrue, string valueIfFalse) => new HtmlString(HttpUtility.HtmlEncode(content.IsAncestor(other) ? valueIfTrue : valueIfFalse));
public static IHtmlContent IsAncestorOrSelf(this IPublishedContent content, IPublishedContent other, string valueIfTrue) => content.IsAncestorOrSelf(other, valueIfTrue, string.Empty);
/// <summary>
/// If the specified <paramref name="content" /> is an ancestor of <paramref name="other" /> or are the same, the HTML encoded <paramref name="valueIfTrue" /> will be returned; otherwise, <paramref name="valueIfFalse" />.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="other">The other content.</param>
/// <param name="valueIfTrue">The value if <c>true</c>.</param>
/// <param name="valueIfFalse">The value if <c>false</c>.</param>
/// <returns>
/// The HTML encoded value.
/// </returns>
public static IHtmlContent IsAncestorOrSelf(this IPublishedContent content, IPublishedContent other, string valueIfTrue, string valueIfFalse) => new HtmlString(HttpUtility.HtmlEncode(content.IsAncestorOrSelf(other) ? valueIfTrue : valueIfFalse));
#endregion
}
}