Clean up extension methods (#17051)
Co-authored-by: Andy Butland <abutland73@gmail.com>
This commit is contained in:
@@ -86,8 +86,8 @@ public class AppCaches : IDisposable
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
RuntimeCache.DisposeIfDisposable();
|
||||
RequestCache.DisposeIfDisposable();
|
||||
(RuntimeCache as IDisposable)?.Dispose();
|
||||
(RequestCache as IDisposable)?.Dispose();
|
||||
IsolatedCaches.Dispose();
|
||||
}
|
||||
|
||||
|
||||
@@ -81,9 +81,9 @@ public abstract class AppPolicedCacheDictionary<TKey> : IDisposable
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
foreach (IAppPolicyCache value in _caches.Values)
|
||||
foreach (IDisposable value in _caches.Values.OfType<IDisposable>())
|
||||
{
|
||||
value.DisposeIfDisposable();
|
||||
value.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ public class DeepCloneAppCache : IAppPolicyCache, IDisposable
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
InnerCache.DisposeIfDisposable();
|
||||
(InnerCache as IDisposable)?.Dispose();
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
|
||||
@@ -59,6 +59,7 @@ public class ComponentCollection : BuilderCollectionBase<IAsyncComponent>
|
||||
try
|
||||
{
|
||||
await component.TerminateAsync(isRestarting, cancellationToken);
|
||||
(component as IDisposable)?.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Umbraco.Cms.Core.Extensions;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.DynamicRoot.QuerySteps;
|
||||
|
||||
@@ -30,7 +28,9 @@ public class FurthestAncestorOrSelfDynamicRootQueryStep : IDynamicRootQueryStep
|
||||
}
|
||||
|
||||
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
|
||||
var result = (await _nodeFilterRepository.FurthestAncestorOrSelfAsync(origins, filter))?.ToSingleItemCollection() ?? Array.Empty<Guid>();
|
||||
var result = (await _nodeFilterRepository.FurthestAncestorOrSelfAsync(origins, filter)) is Guid key
|
||||
? [key]
|
||||
: Array.Empty<Guid>();
|
||||
|
||||
return Attempt<ICollection<Guid>>.Succeed(result);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Umbraco.Cms.Core.Extensions;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.DynamicRoot.QuerySteps;
|
||||
|
||||
@@ -30,7 +28,9 @@ public class NearestAncestorOrSelfDynamicRootQueryStep : IDynamicRootQueryStep
|
||||
}
|
||||
|
||||
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
|
||||
var result = (await _nodeFilterRepository.NearestAncestorOrSelfAsync(origins, filter))?.ToSingleItemCollection() ?? Array.Empty<Guid>();
|
||||
var result = (await _nodeFilterRepository.NearestAncestorOrSelfAsync(origins, filter)) is Guid key
|
||||
? [key]
|
||||
: Array.Empty<Guid>();
|
||||
|
||||
return Attempt<ICollection<Guid>>.Succeed(result);
|
||||
}
|
||||
|
||||
@@ -42,20 +42,6 @@ public static class AssemblyExtensions
|
||||
return _rootDir;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file used to load the assembly
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("This extension method is no longer used and will be removed in Umbraco 17.")]
|
||||
public static FileInfo GetAssemblyFile(this Assembly assembly)
|
||||
{
|
||||
var codeBase = assembly.Location;
|
||||
var uri = new Uri(codeBase);
|
||||
var path = uri.LocalPath;
|
||||
return new FileInfo(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the assembly is the App_Code assembly
|
||||
/// </summary>
|
||||
@@ -90,25 +76,6 @@ public static class AssemblyExtensions
|
||||
// only way I can figure out how to test is by the name
|
||||
assembly.FullName!.StartsWith("App_global.asax");
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file used to load the assembly
|
||||
/// </summary>
|
||||
/// <param name="assemblyName"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("This extension method is no longer used and will be removed in Umbraco 17.")]
|
||||
public static FileInfo? GetAssemblyFile(this AssemblyName assemblyName)
|
||||
{
|
||||
var codeBase = assemblyName.CodeBase;
|
||||
if (!string.IsNullOrEmpty(codeBase))
|
||||
{
|
||||
var uri = new Uri(codeBase);
|
||||
var path = uri.LocalPath;
|
||||
return new FileInfo(path);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the assembly informational version for the specified <paramref name="assembly" />.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace Umbraco.Cms.Core.Extensions;
|
||||
|
||||
public static class CollectionExtensions
|
||||
{
|
||||
[Obsolete("Please replace uses of this extension method with collection expression. This method will be removed in Umbraco 17.")]
|
||||
public static ICollection<T> ToSingleItemCollection<T>(this T item) =>
|
||||
new T[] { item };
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Data;
|
||||
|
||||
namespace Umbraco.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Static and extension methods for the DataTable object
|
||||
/// </summary>
|
||||
public static class DataTableExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a DataTable with the specified alias and columns and uses a callback to populate the headers.
|
||||
/// </summary>
|
||||
/// <param name="tableAlias"></param>
|
||||
/// <param name="getHeaders"></param>
|
||||
/// <param name="rowData"> </param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This has been migrated from the Node class and uses proper locking now. It is now used by the Node class and the
|
||||
/// DynamicPublishedContent extensions for legacy reasons.
|
||||
/// </remarks>
|
||||
[Obsolete("This no longer has a use in Umbraco and so will be removed in Umbraco 17.")]
|
||||
public static DataTable GenerateDataTable(
|
||||
string tableAlias,
|
||||
Func<string, IEnumerable<KeyValuePair<string, string>>> getHeaders,
|
||||
Func<IEnumerable<Tuple<IEnumerable<KeyValuePair<string, object?>>, IEnumerable<KeyValuePair<string, object?>>>>>
|
||||
rowData)
|
||||
{
|
||||
var dt = new DataTable(tableAlias);
|
||||
|
||||
// get all row data
|
||||
Tuple<IEnumerable<KeyValuePair<string, object?>>, IEnumerable<KeyValuePair<string, object?>>>[] tableData =
|
||||
rowData().ToArray();
|
||||
|
||||
// get all headers
|
||||
IDictionary<string, string> propertyHeaders = GetPropertyHeaders(tableAlias, getHeaders);
|
||||
foreach (KeyValuePair<string, string> h in propertyHeaders)
|
||||
{
|
||||
dt.Columns.Add(new DataColumn(h.Value));
|
||||
}
|
||||
|
||||
// add row data
|
||||
foreach (Tuple<IEnumerable<KeyValuePair<string, object?>>, IEnumerable<KeyValuePair<string, object?>>> r in
|
||||
tableData)
|
||||
{
|
||||
dt.PopulateRow(
|
||||
propertyHeaders,
|
||||
r.Item1,
|
||||
r.Item2);
|
||||
}
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to return this ugly object
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is for legacy code, I didn't want to go creating custom classes for these
|
||||
/// </remarks>
|
||||
[Obsolete("This no longer has a use in Umbraco and so will be removed in Umbraco 17.")]
|
||||
public static List<Tuple<IEnumerable<KeyValuePair<string, object?>>, IEnumerable<KeyValuePair<string, object?>>>>
|
||||
CreateTableData() =>
|
||||
new List<Tuple<IEnumerable<KeyValuePair<string, object?>>, IEnumerable<KeyValuePair<string, object?>>>>();
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to deal with these ugly objects
|
||||
/// </summary>
|
||||
/// <param name="rowData"></param>
|
||||
/// <param name="standardVals"></param>
|
||||
/// <param name="userVals"></param>
|
||||
/// <remarks>
|
||||
/// This is for legacy code, I didn't want to go creating custom classes for these
|
||||
/// </remarks>
|
||||
[Obsolete("This no longer has a use in Umbraco and so will be removed in Umbraco 17.")]
|
||||
public static void AddRowData(
|
||||
List<Tuple<IEnumerable<KeyValuePair<string, object?>>, IEnumerable<KeyValuePair<string, object?>>>> rowData,
|
||||
IEnumerable<KeyValuePair<string, object?>> standardVals,
|
||||
IEnumerable<KeyValuePair<string, object?>> userVals) =>
|
||||
rowData.Add(new Tuple<IEnumerable<KeyValuePair<string, object?>>, IEnumerable<KeyValuePair<string, object?>>>(
|
||||
standardVals,
|
||||
userVals));
|
||||
|
||||
private static IDictionary<string, string> GetPropertyHeaders(
|
||||
string alias,
|
||||
Func<string, IEnumerable<KeyValuePair<string, string>>> getHeaders)
|
||||
{
|
||||
IEnumerable<KeyValuePair<string, string>> headers = getHeaders(alias);
|
||||
var def = headers.ToDictionary(pt => pt.Key, pt => pt.Value);
|
||||
return def;
|
||||
}
|
||||
|
||||
private static void PopulateRow(
|
||||
this DataTable dt,
|
||||
IDictionary<string, string> aliasesToNames,
|
||||
IEnumerable<KeyValuePair<string, object?>> standardVals,
|
||||
IEnumerable<KeyValuePair<string, object?>> userPropertyVals)
|
||||
{
|
||||
DataRow dr = dt.NewRow();
|
||||
foreach (KeyValuePair<string, object?> r in standardVals)
|
||||
{
|
||||
dr[r.Key] = r.Value;
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, object?> p in userPropertyVals.Where(p => p.Value != null))
|
||||
{
|
||||
dr[aliasesToNames[p.Key]] = p.Value;
|
||||
}
|
||||
|
||||
dt.Rows.Add(dr);
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Diagnostics;
|
||||
using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Extensions;
|
||||
|
||||
public static class DelegateExtensions
|
||||
{
|
||||
[Obsolete("This method is no longer used in Umbraco. The method will be removed in Umbraco 17.")]
|
||||
public static Attempt<T?> RetryUntilSuccessOrTimeout<T>(this Func<Attempt<T?>> task, TimeSpan timeout, TimeSpan pause)
|
||||
{
|
||||
if (pause.TotalMilliseconds < 0)
|
||||
{
|
||||
throw new ArgumentException("pause must be >= 0 milliseconds");
|
||||
}
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
do
|
||||
{
|
||||
Attempt<T?> result = task();
|
||||
if (result.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
Thread.Sleep((int)pause.TotalMilliseconds);
|
||||
}
|
||||
while (stopwatch.Elapsed < timeout);
|
||||
|
||||
return Attempt<T?>.Fail();
|
||||
}
|
||||
|
||||
[Obsolete("This method is no longer used in Umbraco. The method will be removed in Umbraco 17.")]
|
||||
public static Attempt<T?> RetryUntilSuccessOrMaxAttempts<T>(this Func<int, Attempt<T?>> task, int totalAttempts, TimeSpan pause)
|
||||
{
|
||||
if (pause.TotalMilliseconds < 0)
|
||||
{
|
||||
throw new ArgumentException("pause must be >= 0 milliseconds");
|
||||
}
|
||||
|
||||
var attempts = 0;
|
||||
do
|
||||
{
|
||||
attempts++;
|
||||
Attempt<T?> result = task(attempts);
|
||||
if (result.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
Thread.Sleep((int)pause.TotalMilliseconds);
|
||||
}
|
||||
while (attempts < totalAttempts);
|
||||
|
||||
return Attempt<T?>.Fail();
|
||||
}
|
||||
}
|
||||
@@ -260,7 +260,7 @@ public static class DictionaryExtensions
|
||||
/// </summary>
|
||||
/// <param name="d"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToQueryString(this IDictionary<string, object> d)
|
||||
public static string ToQueryString(this IDictionary<string, object?> d)
|
||||
{
|
||||
if (!d.Any())
|
||||
{
|
||||
@@ -268,7 +268,7 @@ public static class DictionaryExtensions
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
foreach (KeyValuePair<string, object> i in d)
|
||||
foreach (KeyValuePair<string, object?> i in d)
|
||||
{
|
||||
builder.Append(WebUtility.UrlEncode(i.Key));
|
||||
builder.Append('=');
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods to <see cref="Enum"/>.
|
||||
/// </summary>
|
||||
public static class EnumExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether any of the flags/bits are set within the enum value.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The enum type.</typeparam>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="flags">The flags.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if any of the flags/bits are set within the enum value; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
[Obsolete("This method is no longer used in Umbraco. The method will be removed in Umbraco 17.")]
|
||||
public static bool HasFlagAny<T>(this T value, T flags)
|
||||
where T : Enum
|
||||
{
|
||||
var v = Convert.ToUInt64(value);
|
||||
var f = Convert.ToUInt64(flags);
|
||||
|
||||
return (v & f) > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
namespace Umbraco.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for the <see cref="KeyValuePair{TKey,TValue}" /> struct.
|
||||
/// </summary>
|
||||
public static class KeyValuePairExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements key/value pair deconstruction.
|
||||
/// </summary>
|
||||
/// <remarks>Allows for <c>foreach ((var k, var v) in ...)</c>.</remarks>
|
||||
[Obsolete("Please replace uses of this extension method with native language features. This method will be removed in Umbraco 17.")]
|
||||
public static void Deconstruct<TKey, TValue>(this KeyValuePair<TKey, TValue> kvp, out TKey key, out TValue value)
|
||||
{
|
||||
key = kvp.Key;
|
||||
value = kvp.Value;
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Specialized;
|
||||
using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Extensions;
|
||||
|
||||
public static class NameValueCollectionExtensions
|
||||
{
|
||||
[Obsolete("This method is no longer used in Umbraco. The method will be removed in Umbraco 17.")]
|
||||
public static IEnumerable<KeyValuePair<string?, string?>> AsEnumerable(this NameValueCollection nvc)
|
||||
{
|
||||
foreach (var key in nvc.AllKeys)
|
||||
{
|
||||
yield return new KeyValuePair<string?, string?>(key, nvc[key]);
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("This method is no longer used in Umbraco. The method will be removed in Umbraco 17.")]
|
||||
public static bool ContainsKey(this NameValueCollection collection, string key) =>
|
||||
collection.Keys.Cast<object>().Any(k => (string)k == key);
|
||||
|
||||
[Obsolete("This method is no longer used in Umbraco. The method will be removed in Umbraco 17.")]
|
||||
public static T? GetValue<T>(this NameValueCollection collection, string key, T defaultIfNotFound)
|
||||
{
|
||||
if (collection.ContainsKey(key) == false)
|
||||
{
|
||||
return defaultIfNotFound;
|
||||
}
|
||||
|
||||
var val = collection[key];
|
||||
if (val == null)
|
||||
{
|
||||
return defaultIfNotFound;
|
||||
}
|
||||
|
||||
Attempt<T> result = val.TryConvertTo<T>();
|
||||
|
||||
return result.Success ? result.Result : defaultIfNotFound;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Xml;
|
||||
@@ -15,81 +14,148 @@ using Umbraco.Cms.Core.Collections;
|
||||
namespace Umbraco.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides object extension methods.
|
||||
/// Provides object extension methods.
|
||||
/// </summary>
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Type, Type?> NullableGenericCache = new();
|
||||
private static readonly ConcurrentDictionary<CompositeTypeTypeKey, TypeConverter?> InputTypeConverterCache = new();
|
||||
|
||||
private static readonly ConcurrentDictionary<CompositeTypeTypeKey, TypeConverter?> DestinationTypeConverterCache =
|
||||
new();
|
||||
|
||||
private static readonly ConcurrentDictionary<CompositeTypeTypeKey, bool> AssignableTypeCache = new();
|
||||
private static readonly ConcurrentDictionary<Type, bool> BoolConvertCache = new();
|
||||
|
||||
private static readonly char[] NumberDecimalSeparatorsToNormalize = { '.', ',' };
|
||||
private static readonly CustomBooleanTypeConverter CustomBooleanTypeConverter = new();
|
||||
|
||||
// private static readonly ConcurrentDictionary<Type, Func<object>> ObjectFactoryCache = new ConcurrentDictionary<Type, Func<object>>();
|
||||
private static readonly ConcurrentDictionary<Type, Type?> _nullableGenericCache = new();
|
||||
private static readonly ConcurrentDictionary<CompositeTypeTypeKey, TypeConverter?> _inputTypeConverterCache = new();
|
||||
private static readonly ConcurrentDictionary<CompositeTypeTypeKey, TypeConverter?> _destinationTypeConverterCache = new();
|
||||
private static readonly ConcurrentDictionary<CompositeTypeTypeKey, bool> _assignableTypeCache = new();
|
||||
private static readonly ConcurrentDictionary<Type, bool> _boolConvertCache = new();
|
||||
private static readonly char[] _numberDecimalSeparatorsToNormalize = ['.', ','];
|
||||
private static readonly CustomBooleanTypeConverter _customBooleanTypeConverter = new();
|
||||
|
||||
/// <summary>
|
||||
/// Returns an XML serialized safe string representation for the value and type.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<T> AsEnumerableOfOne<T>(this T input) => Enumerable.Repeat(input, 1);
|
||||
/// <typeparam name="T">The type of the value.</typeparam>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns>
|
||||
/// The XML serialized safe string representation.
|
||||
/// </returns>
|
||||
public static string ToXmlString<T>(this object value) => value.ToXmlString(typeof(T));
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the object if it implements <see cref="IDisposable" />.
|
||||
/// Returns an XML serialized safe string representation for the value and type.
|
||||
/// </summary>
|
||||
/// <param name="input">The object.</param>
|
||||
[Obsolete("Please replace uses of this extension method with (input as IDisposable)?.Dispose(). This extension method will be removed in Umbraco 17.")]
|
||||
public static void DisposeIfDisposable(this object input)
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="type">The type of the value. This can only be a primitive type or <see cref="Guid" /> and <see cref="T:byte[]" />, otherwise an exception is thrown.</param>
|
||||
/// <returns>
|
||||
/// The XML serialized safe string representation.
|
||||
/// </returns>
|
||||
public static string ToXmlString(this object value, Type type)
|
||||
{
|
||||
if (input is IDisposable disposable)
|
||||
if (value == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// ignore if it is already disposed
|
||||
}
|
||||
return string.Empty;
|
||||
|
||||
}
|
||||
|
||||
if (type == typeof(string))
|
||||
{
|
||||
return value.ToString().OrIfNullOrWhiteSpace(string.Empty);
|
||||
}
|
||||
|
||||
if (type == typeof(bool))
|
||||
{
|
||||
return XmlConvert.ToString((bool)value);
|
||||
}
|
||||
|
||||
if (type == typeof(byte))
|
||||
{
|
||||
return XmlConvert.ToString((byte)value);
|
||||
}
|
||||
|
||||
if (type == typeof(char))
|
||||
{
|
||||
return XmlConvert.ToString((char)value);
|
||||
}
|
||||
|
||||
if (type == typeof(DateTime))
|
||||
{
|
||||
return XmlConvert.ToString((DateTime)value, XmlDateTimeSerializationMode.Unspecified);
|
||||
}
|
||||
|
||||
if (type == typeof(DateTimeOffset))
|
||||
{
|
||||
return XmlConvert.ToString((DateTimeOffset)value);
|
||||
}
|
||||
|
||||
if (type == typeof(decimal))
|
||||
{
|
||||
return XmlConvert.ToString((decimal)value);
|
||||
}
|
||||
|
||||
if (type == typeof(double))
|
||||
{
|
||||
return XmlConvert.ToString((double)value);
|
||||
}
|
||||
|
||||
if (type == typeof(float))
|
||||
{
|
||||
return XmlConvert.ToString((float)value);
|
||||
}
|
||||
|
||||
if (type == typeof(Guid))
|
||||
{
|
||||
return XmlConvert.ToString((Guid)value);
|
||||
}
|
||||
|
||||
if (type == typeof(int))
|
||||
{
|
||||
return XmlConvert.ToString((int)value);
|
||||
}
|
||||
|
||||
if (type == typeof(long))
|
||||
{
|
||||
return XmlConvert.ToString((long)value);
|
||||
}
|
||||
|
||||
if (type == typeof(sbyte))
|
||||
{
|
||||
return XmlConvert.ToString((sbyte)value);
|
||||
}
|
||||
|
||||
if (type == typeof(short))
|
||||
{
|
||||
return XmlConvert.ToString((short)value);
|
||||
}
|
||||
|
||||
if (type == typeof(TimeSpan))
|
||||
{
|
||||
return XmlConvert.ToString((TimeSpan)value);
|
||||
}
|
||||
|
||||
if (type == typeof(uint))
|
||||
{
|
||||
return XmlConvert.ToString((uint)value);
|
||||
}
|
||||
|
||||
if (type == typeof(ulong))
|
||||
{
|
||||
return XmlConvert.ToString((ulong)value);
|
||||
}
|
||||
|
||||
if (type == typeof(ushort))
|
||||
{
|
||||
return XmlConvert.ToString((ushort)value);
|
||||
}
|
||||
|
||||
throw new NotSupportedException($"Cannot convert type {type.FullName} to a string using ToXmlString, as it is not supported by XmlConvert.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a shortcut way of safely casting an input when you cannot guarantee the <typeparamref name="T" /> is
|
||||
/// an instance type (i.e., when the C# AS keyword is not applicable).
|
||||
/// Attempts to convert the input object to the output type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="T">The type to convert to.</typeparam>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("This extension method is not longer used and will be removed in Umbraco 17.")]
|
||||
public static T? SafeCast<T>(this object input)
|
||||
{
|
||||
if (ReferenceEquals(null, input) || ReferenceEquals(default(T), input))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
if (input is T variable)
|
||||
{
|
||||
return variable;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to convert the input object to the output type.
|
||||
/// </summary>
|
||||
/// <remarks>This code is an optimized version of the original Umbraco method</remarks>
|
||||
/// <typeparam name="T">The type to convert to</typeparam>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <returns>The <see cref="Attempt{T}" /></returns>
|
||||
/// <returns>
|
||||
/// The <see cref="Attempt{T}" />.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This code is an optimized version of the original Umbraco method.
|
||||
/// </remarks>
|
||||
public static Attempt<T> TryConvertTo<T>(this object? input)
|
||||
{
|
||||
Attempt<object?> result = TryConvertTo(input, typeof(T));
|
||||
@@ -116,19 +182,23 @@ public static class ObjectExtensions
|
||||
{
|
||||
return Attempt<T>.Succeed((T)input);
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Attempt<T>.Fail(e);
|
||||
return Attempt<T>.Fail(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to convert the input object to the output type.
|
||||
/// Attempts to convert the input object to the output type.
|
||||
/// </summary>
|
||||
/// <remarks>This code is an optimized version of the original Umbraco method</remarks>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="target">The type to convert to</param>
|
||||
/// <returns>The <see cref="Attempt{Object}" /></returns>
|
||||
/// <param name="target">The type to convert to.</param>
|
||||
/// <returns>
|
||||
/// The <see cref="T:Attempt{object?}" />.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This code is an optimized version of the original Umbraco method.
|
||||
/// </remarks>
|
||||
public static Attempt<object?> TryConvertTo(this object? input, Type target)
|
||||
{
|
||||
if (target == null)
|
||||
@@ -158,7 +228,7 @@ public static class ObjectExtensions
|
||||
return Attempt.Succeed(input);
|
||||
}
|
||||
|
||||
// Check for string so that overloaders of ToString() can take advantage of the conversion.
|
||||
// Check for string so that overloads of ToString() can take advantage of the conversion.
|
||||
if (target == typeof(string))
|
||||
{
|
||||
return Attempt<object?>.Succeed(input.ToString());
|
||||
@@ -225,13 +295,13 @@ public static class ObjectExtensions
|
||||
{
|
||||
if (GetCachedCanConvertToBoolean(inputType))
|
||||
{
|
||||
return Attempt.Succeed(CustomBooleanTypeConverter.ConvertFrom(input!));
|
||||
return Attempt.Succeed(_customBooleanTypeConverter.ConvertFrom(input!));
|
||||
}
|
||||
}
|
||||
|
||||
if (target == typeof(DateTime) && input is DateTimeOffset dateTimeOffset)
|
||||
{
|
||||
// IMPORTANT: for compatability with various editors, we must discard any Offset information and assume UTC time here
|
||||
// IMPORTANT: for compatibility with various editors, we must discard any Offset information and assume UTC time here
|
||||
return Attempt.Succeed((object?)new DateTime(
|
||||
new DateOnly(dateTimeOffset.Year, dateTimeOffset.Month, dateTimeOffset.Day),
|
||||
new TimeOnly(dateTimeOffset.Hour, dateTimeOffset.Minute, dateTimeOffset.Second, dateTimeOffset.Millisecond, dateTimeOffset.Microsecond),
|
||||
@@ -240,7 +310,7 @@ public static class ObjectExtensions
|
||||
|
||||
if (target == typeof(DateTimeOffset) && input is DateTime dateTime)
|
||||
{
|
||||
// IMPORTANT: for compatability with various editors, we must discard any DateTimeKind information and assume UTC time here
|
||||
// IMPORTANT: for compatibility with various editors, we must discard any DateTimeKind information and assume UTC time here
|
||||
return Attempt.Succeed((object?)new DateTimeOffset(
|
||||
new DateOnly(dateTime.Year, dateTime.Month, dateTime.Day),
|
||||
new TimeOnly(dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond, dateTime.Microsecond),
|
||||
@@ -281,102 +351,18 @@ public static class ObjectExtensions
|
||||
return Attempt<object?>.Fail();
|
||||
}
|
||||
|
||||
// public enum PropertyNamesCaseType
|
||||
// {
|
||||
// CamelCase,
|
||||
// CaseInsensitive
|
||||
// }
|
||||
|
||||
///// <summary>
|
||||
///// Convert an object to a JSON string with camelCase formatting
|
||||
///// </summary>
|
||||
///// <param name="obj"></param>
|
||||
///// <returns></returns>
|
||||
// public static string ToJsonString(this object obj)
|
||||
// {
|
||||
// return obj.ToJsonString(PropertyNamesCaseType.CamelCase);
|
||||
// }
|
||||
|
||||
///// <summary>
|
||||
///// Convert an object to a JSON string with the specified formatting
|
||||
///// </summary>
|
||||
///// <param name="obj">The obj.</param>
|
||||
///// <param name="propertyNamesCaseType">Type of the property names case.</param>
|
||||
///// <returns></returns>
|
||||
// public static string ToJsonString(this object obj, PropertyNamesCaseType propertyNamesCaseType)
|
||||
// {
|
||||
// var type = obj.GetType();
|
||||
// var dateTimeStyle = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
// if (type.IsPrimitive || typeof(string).IsAssignableFrom(type))
|
||||
// {
|
||||
// return obj.ToString();
|
||||
// }
|
||||
|
||||
// if (typeof(DateTime).IsAssignableFrom(type) || typeof(DateTimeOffset).IsAssignableFrom(type))
|
||||
// {
|
||||
// return Convert.ToDateTime(obj).ToString(dateTimeStyle);
|
||||
// }
|
||||
|
||||
// var serializer = new JsonSerializer();
|
||||
|
||||
// switch (propertyNamesCaseType)
|
||||
// {
|
||||
// case PropertyNamesCaseType.CamelCase:
|
||||
// serializer.ContractResolver = new CamelCasePropertyNamesContractResolver();
|
||||
// break;
|
||||
// }
|
||||
|
||||
// var dateTimeConverter = new IsoDateTimeConverter
|
||||
// {
|
||||
// DateTimeStyles = System.Globalization.DateTimeStyles.None,
|
||||
// DateTimeFormat = dateTimeStyle
|
||||
// };
|
||||
|
||||
// if (typeof(IDictionary).IsAssignableFrom(type))
|
||||
// {
|
||||
// return JObject.FromObject(obj, serializer).ToString(Formatting.None, dateTimeConverter);
|
||||
// }
|
||||
|
||||
// if (type.IsArray || (typeof(IEnumerable).IsAssignableFrom(type)))
|
||||
// {
|
||||
// return JArray.FromObject(obj, serializer).ToString(Formatting.None, dateTimeConverter);
|
||||
// }
|
||||
|
||||
// return JObject.FromObject(obj, serializer).ToString(Formatting.None, dateTimeConverter);
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// Converts an object into a dictionary
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TProperty"></typeparam>
|
||||
/// <typeparam name="TVal"> </typeparam>
|
||||
/// <param name="o"></param>
|
||||
/// <param name="ignoreProperties"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("This method is no longer used in Umbraco. The method will be removed in Umbraco 17.")]
|
||||
public static IDictionary<string, TVal>? ToDictionary<T, TProperty, TVal>(
|
||||
this T o,
|
||||
params Expression<Func<T, TProperty>>[] ignoreProperties) => o?.ToDictionary<TVal>(ignoreProperties
|
||||
.Select(e => o.GetPropertyInfo(e)).Select(propInfo => propInfo.Name).ToArray());
|
||||
|
||||
internal static void CheckThrowObjectDisposed(this IDisposable disposable, bool isDisposed, string objectname)
|
||||
{
|
||||
// TODO: Localize this exception
|
||||
if (isDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException(objectname);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to convert the input string to the output type.
|
||||
/// Attempts to convert the input string to the output type.
|
||||
/// </summary>
|
||||
/// <remarks>This code is an optimized version of the original Umbraco method</remarks>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="target">The type to convert to</param>
|
||||
/// <returns>The <see cref="Nullable{Attempt}" /></returns>
|
||||
/// <returns>
|
||||
/// The <see cref="T:Attempt{object?}" />
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This code is an optimized version of the original Umbraco method.
|
||||
/// </remarks>
|
||||
private static Attempt<object?>? TryConvertToFromString(this string input, Type target)
|
||||
{
|
||||
// Easy
|
||||
@@ -529,143 +515,7 @@ public static class ObjectExtensions
|
||||
return null; // we can't decide...
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Turns object into dictionary
|
||||
/// </summary>
|
||||
/// <param name="o"></param>
|
||||
/// <param name="ignoreProperties">Properties to ignore</param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use of this can be replaced with RouteValueDictionary or HtmlHelper.AnonymousObjectToHtmlAttributes(). The method will be removed in Umbraco 17.")]
|
||||
public static IDictionary<string, TVal> ToDictionary<TVal>(this object o, params string[] ignoreProperties)
|
||||
{
|
||||
if (o != null)
|
||||
{
|
||||
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(o);
|
||||
var d = new Dictionary<string, TVal>();
|
||||
foreach (PropertyDescriptor prop in props.Cast<PropertyDescriptor>()
|
||||
.Where(x => ignoreProperties.Contains(x.Name) == false))
|
||||
{
|
||||
var val = prop.GetValue(o);
|
||||
if (val != null)
|
||||
{
|
||||
d.Add(prop.Name, (TVal)val);
|
||||
}
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
return new Dictionary<string, TVal>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an XmlSerialized safe string representation for the value
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="type">The Type can only be a primitive type or Guid and byte[] otherwise an exception is thrown</param>
|
||||
/// <returns></returns>
|
||||
public static string ToXmlString(this object value, Type type)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (type == typeof(string))
|
||||
{
|
||||
return value.ToString().IsNullOrWhiteSpace() ? string.Empty : value.ToString()!;
|
||||
}
|
||||
|
||||
if (type == typeof(bool))
|
||||
{
|
||||
return XmlConvert.ToString((bool)value);
|
||||
}
|
||||
|
||||
if (type == typeof(byte))
|
||||
{
|
||||
return XmlConvert.ToString((byte)value);
|
||||
}
|
||||
|
||||
if (type == typeof(char))
|
||||
{
|
||||
return XmlConvert.ToString((char)value);
|
||||
}
|
||||
|
||||
if (type == typeof(DateTime))
|
||||
{
|
||||
return XmlConvert.ToString((DateTime)value, XmlDateTimeSerializationMode.Unspecified);
|
||||
}
|
||||
|
||||
if (type == typeof(DateTimeOffset))
|
||||
{
|
||||
return XmlConvert.ToString((DateTimeOffset)value);
|
||||
}
|
||||
|
||||
if (type == typeof(decimal))
|
||||
{
|
||||
return XmlConvert.ToString((decimal)value);
|
||||
}
|
||||
|
||||
if (type == typeof(double))
|
||||
{
|
||||
return XmlConvert.ToString((double)value);
|
||||
}
|
||||
|
||||
if (type == typeof(float))
|
||||
{
|
||||
return XmlConvert.ToString((float)value);
|
||||
}
|
||||
|
||||
if (type == typeof(Guid))
|
||||
{
|
||||
return XmlConvert.ToString((Guid)value);
|
||||
}
|
||||
|
||||
if (type == typeof(int))
|
||||
{
|
||||
return XmlConvert.ToString((int)value);
|
||||
}
|
||||
|
||||
if (type == typeof(long))
|
||||
{
|
||||
return XmlConvert.ToString((long)value);
|
||||
}
|
||||
|
||||
if (type == typeof(sbyte))
|
||||
{
|
||||
return XmlConvert.ToString((sbyte)value);
|
||||
}
|
||||
|
||||
if (type == typeof(short))
|
||||
{
|
||||
return XmlConvert.ToString((short)value);
|
||||
}
|
||||
|
||||
if (type == typeof(TimeSpan))
|
||||
{
|
||||
return XmlConvert.ToString((TimeSpan)value);
|
||||
}
|
||||
|
||||
if (type == typeof(uint))
|
||||
{
|
||||
return XmlConvert.ToString((uint)value);
|
||||
}
|
||||
|
||||
if (type == typeof(ulong))
|
||||
{
|
||||
return XmlConvert.ToString((ulong)value);
|
||||
}
|
||||
|
||||
if (type == typeof(ushort))
|
||||
{
|
||||
return XmlConvert.ToString((ushort)value);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Cannot convert type " + type.FullName +
|
||||
" to a string using ToXmlString as it is not supported by XmlConvert");
|
||||
}
|
||||
|
||||
internal static string? ToDebugString(this object? obj, int levels = 0)
|
||||
private static string? ToDebugString(this object? obj, int levels = 0)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
@@ -738,35 +588,6 @@ public static class ObjectExtensions
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to serialize the value to an XmlString using ToXmlString
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
internal static Attempt<string?> TryConvertToXmlString(this object value, Type type)
|
||||
{
|
||||
try
|
||||
{
|
||||
var output = value.ToXmlString(type);
|
||||
return Attempt.Succeed(output);
|
||||
}
|
||||
catch (NotSupportedException ex)
|
||||
{
|
||||
return Attempt<string?>.Fail(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an XmlSerialized safe string representation for the value and type
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToXmlString<T>(this object value) => value.ToXmlString(typeof(T));
|
||||
|
||||
public static Guid AsGuid(this object value) => value is Guid guid ? guid : Guid.Empty;
|
||||
|
||||
private static string? GetEnumPropertyDebugString(object enumItem, int levels)
|
||||
{
|
||||
try
|
||||
@@ -795,7 +616,7 @@ public static class ObjectExtensions
|
||||
private static string NormalizeNumberDecimalSeparator(string s)
|
||||
{
|
||||
var normalized = Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator[0];
|
||||
return s.ReplaceMany(NumberDecimalSeparatorsToNormalize, normalized);
|
||||
return s.ReplaceMany(_numberDecimalSeparatorsToNormalize, normalized);
|
||||
}
|
||||
|
||||
// gets a converter for source, that can convert to target, or null if none exists
|
||||
@@ -804,7 +625,7 @@ public static class ObjectExtensions
|
||||
{
|
||||
var key = new CompositeTypeTypeKey(source, target);
|
||||
|
||||
if (InputTypeConverterCache.TryGetValue(key, out TypeConverter? typeConverter))
|
||||
if (_inputTypeConverterCache.TryGetValue(key, out TypeConverter? typeConverter))
|
||||
{
|
||||
return typeConverter;
|
||||
}
|
||||
@@ -812,10 +633,10 @@ public static class ObjectExtensions
|
||||
TypeConverter converter = TypeDescriptor.GetConverter(source);
|
||||
if (converter.CanConvertTo(target))
|
||||
{
|
||||
return InputTypeConverterCache[key] = converter;
|
||||
return _inputTypeConverterCache[key] = converter;
|
||||
}
|
||||
|
||||
InputTypeConverterCache[key] = null;
|
||||
_inputTypeConverterCache[key] = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -825,7 +646,7 @@ public static class ObjectExtensions
|
||||
{
|
||||
var key = new CompositeTypeTypeKey(source, target);
|
||||
|
||||
if (DestinationTypeConverterCache.TryGetValue(key, out TypeConverter? typeConverter))
|
||||
if (_destinationTypeConverterCache.TryGetValue(key, out TypeConverter? typeConverter))
|
||||
{
|
||||
return typeConverter;
|
||||
}
|
||||
@@ -833,10 +654,10 @@ public static class ObjectExtensions
|
||||
TypeConverter converter = TypeDescriptor.GetConverter(target);
|
||||
if (converter.CanConvertFrom(source))
|
||||
{
|
||||
return DestinationTypeConverterCache[key] = converter;
|
||||
return _destinationTypeConverterCache[key] = converter;
|
||||
}
|
||||
|
||||
DestinationTypeConverterCache[key] = null;
|
||||
_destinationTypeConverterCache[key] = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -844,7 +665,7 @@ public static class ObjectExtensions
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static Type? GetCachedGenericNullableType(Type type)
|
||||
{
|
||||
if (NullableGenericCache.TryGetValue(type, out Type? underlyingType))
|
||||
if (_nullableGenericCache.TryGetValue(type, out Type? underlyingType))
|
||||
{
|
||||
return underlyingType;
|
||||
}
|
||||
@@ -852,10 +673,10 @@ public static class ObjectExtensions
|
||||
if (type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
{
|
||||
Type? underlying = Nullable.GetUnderlyingType(type);
|
||||
return NullableGenericCache[type] = underlying;
|
||||
return _nullableGenericCache[type] = underlying;
|
||||
}
|
||||
|
||||
NullableGenericCache[type] = null;
|
||||
_nullableGenericCache[type] = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -864,7 +685,7 @@ public static class ObjectExtensions
|
||||
private static bool GetCachedCanAssign(object input, Type source, Type target)
|
||||
{
|
||||
var key = new CompositeTypeTypeKey(source, target);
|
||||
if (AssignableTypeCache.TryGetValue(key, out var canConvert))
|
||||
if (_assignableTypeCache.TryGetValue(key, out var canConvert))
|
||||
{
|
||||
return canConvert;
|
||||
}
|
||||
@@ -873,26 +694,26 @@ public static class ObjectExtensions
|
||||
// We can use it to very quickly determine whether true/false
|
||||
if (input is IConvertible && target.IsAssignableFrom(source))
|
||||
{
|
||||
return AssignableTypeCache[key] = true;
|
||||
return _assignableTypeCache[key] = true;
|
||||
}
|
||||
|
||||
return AssignableTypeCache[key] = false;
|
||||
return _assignableTypeCache[key] = false;
|
||||
}
|
||||
|
||||
// determines whether a type can be converted to boolean
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool GetCachedCanConvertToBoolean(Type type)
|
||||
{
|
||||
if (BoolConvertCache.TryGetValue(type, out var result))
|
||||
if (_boolConvertCache.TryGetValue(type, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (CustomBooleanTypeConverter.CanConvertFrom(type))
|
||||
if (_customBooleanTypeConverter.CanConvertFrom(type))
|
||||
{
|
||||
return BoolConvertCache[type] = true;
|
||||
return _boolConvertCache[type] = true;
|
||||
}
|
||||
|
||||
return BoolConvertCache[type] = false;
|
||||
return _boolConvertCache[type] = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2832,137 +2832,6 @@ public static class PublishedContentExtensions
|
||||
|
||||
#endregion
|
||||
|
||||
#region Axes: children
|
||||
|
||||
/// <summary>
|
||||
/// Gets the children of the content in a DataTable.
|
||||
/// </summary>
|
||||
/// <param name="content">The content.</param>
|
||||
/// <param name="navigationQueryService"></param>
|
||||
/// <param name="publishedStatusFilteringService"></param>
|
||||
/// <param name="contentTypeService">The content type service.</param>
|
||||
/// <param name="mediaTypeService">The media type service.</param>
|
||||
/// <param name="memberTypeService">The member type service.</param>
|
||||
/// <param name="publishedUrlProvider">The published url provider.</param>
|
||||
/// <param name="contentTypeAliasFilter">An optional content type alias.</param>
|
||||
/// <param name="culture">
|
||||
/// The specific culture to filter for. If null is used the current culture is used. (Default is
|
||||
/// null)
|
||||
/// </param>
|
||||
/// <returns>The children of the content.</returns>
|
||||
[Obsolete("This method is no longer used in Umbraco. The method will be removed in Umbraco 17.")]
|
||||
public static DataTable ChildrenAsTable(
|
||||
this IPublishedContent content,
|
||||
INavigationQueryService navigationQueryService,
|
||||
IPublishedStatusFilteringService publishedStatusFilteringService,
|
||||
IContentTypeService contentTypeService,
|
||||
IMediaTypeService mediaTypeService,
|
||||
IMemberTypeService memberTypeService,
|
||||
IPublishedUrlProvider publishedUrlProvider,
|
||||
string contentTypeAliasFilter = "",
|
||||
string? culture = null)
|
||||
=> content.GenerateDataTable(navigationQueryService, publishedStatusFilteringService, contentTypeService, mediaTypeService, memberTypeService, publishedUrlProvider, contentTypeAliasFilter, culture);
|
||||
|
||||
[Obsolete("Use the overload with INavigationQueryService and IPublishedStatusFilteringService, scheduled for removal in v17")]
|
||||
public static DataTable ChildrenAsTable(
|
||||
this IPublishedContent content,
|
||||
IVariationContextAccessor variationContextAccessor,
|
||||
IPublishedCache publishedCache,
|
||||
INavigationQueryService navigationQueryService,
|
||||
IContentTypeService contentTypeService,
|
||||
IMediaTypeService mediaTypeService,
|
||||
IMemberTypeService memberTypeService,
|
||||
IPublishedUrlProvider publishedUrlProvider,
|
||||
string contentTypeAliasFilter = "",
|
||||
string? culture = null)
|
||||
=> content.GenerateDataTable(navigationQueryService, GetPublishedStatusFilteringService(content), contentTypeService, mediaTypeService, memberTypeService, publishedUrlProvider, contentTypeAliasFilter, culture);
|
||||
|
||||
private static DataTable GenerateDataTable(
|
||||
this IPublishedContent content,
|
||||
INavigationQueryService navigationQueryService,
|
||||
IPublishedStatusFilteringService publishedStatusFilteringService,
|
||||
IContentTypeService contentTypeService,
|
||||
IMediaTypeService mediaTypeService,
|
||||
IMemberTypeService memberTypeService,
|
||||
IPublishedUrlProvider publishedUrlProvider,
|
||||
string contentTypeAliasFilter = "",
|
||||
string? culture = null)
|
||||
{
|
||||
IPublishedContent[] children = content.Children(navigationQueryService, publishedStatusFilteringService, culture).ToArray();
|
||||
IPublishedContent? firstNode = contentTypeAliasFilter.IsNullOrWhiteSpace()
|
||||
? children.Length > 0
|
||||
? children.ElementAt(0)
|
||||
: null
|
||||
: children.FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAliasFilter));
|
||||
if (firstNode == null)
|
||||
{
|
||||
// No children found
|
||||
return new DataTable();
|
||||
}
|
||||
|
||||
// use new utility class to create table so that we don't have to maintain code in many places, just one
|
||||
DataTable dt = DataTableExtensions.GenerateDataTable(
|
||||
|
||||
// pass in the alias of the first child node since this is the node type we're rendering headers for
|
||||
firstNode.ContentType.Alias,
|
||||
|
||||
// pass in the callback to extract the Dictionary<string, string> of all defined aliases to their names
|
||||
alias => GetPropertyAliasesAndNames(contentTypeService, mediaTypeService, memberTypeService, alias),
|
||||
() =>
|
||||
{
|
||||
// here we pass in a callback to populate the datatable, yup its a bit ugly but it's already legacy and we just want to maintain code in one place.
|
||||
// create all row data
|
||||
List<Tuple<IEnumerable<KeyValuePair<string, object?>>, IEnumerable<KeyValuePair<string, object?>>>>
|
||||
tableData = DataTableExtensions.CreateTableData();
|
||||
IOrderedEnumerable<IPublishedContent>? children =
|
||||
content.Children(navigationQueryService, publishedStatusFilteringService).OrderBy(x => x.SortOrder);
|
||||
if (children is not null)
|
||||
{
|
||||
// loop through each child and create row data for it
|
||||
foreach (IPublishedContent n in children)
|
||||
{
|
||||
if (contentTypeAliasFilter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
if (n.ContentType.Alias.InvariantEquals(contentTypeAliasFilter) == false)
|
||||
{
|
||||
continue; // skip this one, it doesn't match the filter
|
||||
}
|
||||
}
|
||||
|
||||
var standardVals = new Dictionary<string, object?>
|
||||
{
|
||||
{ "Id", n.Id },
|
||||
{ "NodeName", n.Name(null, culture) },
|
||||
{ "NodeTypeAlias", n.ContentType.Alias },
|
||||
{ "CreateDate", n.CreateDate },
|
||||
{ "UpdateDate", n.UpdateDate },
|
||||
{ "CreatorId", n.CreatorId },
|
||||
{ "WriterId", n.WriterId },
|
||||
{ "Url", n.Url(publishedUrlProvider) },
|
||||
};
|
||||
|
||||
var userVals = new Dictionary<string, object?>();
|
||||
IEnumerable<IPublishedProperty> properties =
|
||||
n.Properties?.Where(p => p.GetSourceValue() is not null) ??
|
||||
Array.Empty<IPublishedProperty>();
|
||||
foreach (IPublishedProperty p in properties)
|
||||
{
|
||||
// probably want the "object value" of the property here...
|
||||
userVals[p.Alias] = p.GetValue();
|
||||
}
|
||||
|
||||
// Add the row data
|
||||
DataTableExtensions.AddRowData(tableData, standardVals, userVals);
|
||||
}
|
||||
}
|
||||
|
||||
return tableData;
|
||||
});
|
||||
return dt;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PropertyAliasesAndNames
|
||||
|
||||
private static Func<IContentTypeService, IMediaTypeService, IMemberTypeService, string, Dictionary<string, string>>? _getPropertyAliasesAndNames;
|
||||
@@ -3142,17 +3011,6 @@ public static class PublishedContentExtensions
|
||||
where T : class, IPublishedContent
|
||||
=> content.Children<T>(GetNavigationQueryService(content), GetPublishedStatusFilteringService(content), culture);
|
||||
|
||||
[Obsolete("This method is no longer used in Umbraco. The method will be removed in Umbraco 17.")]
|
||||
public static DataTable ChildrenAsTable(
|
||||
this IPublishedContent content,
|
||||
IVariationContextAccessor variationContextAccessor,
|
||||
IContentTypeService contentTypeService,
|
||||
IMediaTypeService mediaTypeService,
|
||||
IMemberTypeService memberTypeService,
|
||||
IPublishedUrlProvider publishedUrlProvider,
|
||||
string contentTypeAliasFilter = "",
|
||||
string? culture = null)
|
||||
=> content.GenerateDataTable(GetNavigationQueryService(content), GetPublishedStatusFilteringService(content), contentTypeService, mediaTypeService, memberTypeService, publishedUrlProvider, contentTypeAliasFilter, culture);
|
||||
|
||||
public static IEnumerable<IPublishedContent> DescendantsOrSelfOfType(
|
||||
this IEnumerable<IPublishedContent> parentNodes,
|
||||
|
||||
@@ -912,7 +912,8 @@ public static class StringExtensions
|
||||
return text;
|
||||
}
|
||||
|
||||
public static string OrIfNullOrWhiteSpace(this string input, string alternative) =>
|
||||
[return: NotNullIfNotNull(nameof(alternative))]
|
||||
public static string? OrIfNullOrWhiteSpace(this string? input, string? alternative) =>
|
||||
!string.IsNullOrWhiteSpace(input)
|
||||
? input
|
||||
: alternative;
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Globalization;
|
||||
|
||||
namespace Umbraco.Extensions;
|
||||
|
||||
public static class ThreadExtensions
|
||||
{
|
||||
[Obsolete("This method is no longer used in Umbraco. The method will be removed in Umbraco 17.")]
|
||||
public static void SanitizeThreadCulture(this Thread thread)
|
||||
{
|
||||
// get the current culture
|
||||
CultureInfo currentCulture = CultureInfo.CurrentCulture;
|
||||
|
||||
// at the top of any culture should be the invariant culture - find it
|
||||
// doing an .Equals comparison ensure that we *will* find it and not loop
|
||||
// endlessly
|
||||
CultureInfo invariantCulture = currentCulture;
|
||||
while (invariantCulture.Equals(CultureInfo.InvariantCulture) == false)
|
||||
{
|
||||
invariantCulture = invariantCulture.Parent;
|
||||
}
|
||||
|
||||
// now that invariant culture should be the same object as CultureInfo.InvariantCulture
|
||||
// yet for some reasons, sometimes it is not - and this breaks anything that loops on
|
||||
// culture.Parent until a reference equality to CultureInfo.InvariantCulture. See, for
|
||||
// example, the following code in PerformanceCounterLib.IsCustomCategory:
|
||||
//
|
||||
// CultureInfo culture = CultureInfo.CurrentCulture;
|
||||
// while (culture != CultureInfo.InvariantCulture)
|
||||
// {
|
||||
// library = GetPerformanceCounterLib(machine, culture);
|
||||
// if (library.IsCustomCategory(category))
|
||||
// return true;
|
||||
// culture = culture.Parent;
|
||||
// }
|
||||
//
|
||||
// The reference comparisons never succeeds, hence the loop never ends, and the
|
||||
// application hangs.
|
||||
//
|
||||
// granted, that comparison should probably be a .Equals comparison, but who knows
|
||||
// how many times the framework assumes that it can do a reference comparison? So,
|
||||
// better fix the cultures.
|
||||
if (ReferenceEquals(invariantCulture, CultureInfo.InvariantCulture))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if we do not have equality, fix cultures by replacing them with a culture with
|
||||
// the same name, but obtained here and now, with a proper invariant top culture
|
||||
thread.CurrentCulture = CultureInfo.GetCultureInfo(thread.CurrentCulture.Name);
|
||||
thread.CurrentUICulture = CultureInfo.GetCultureInfo(thread.CurrentUICulture.Name);
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ public class SerilogLogger : IDisposable
|
||||
IConfiguration configuration) =>
|
||||
CreateWithDefaultConfiguration(hostingEnvironment, loggingConfiguration, configuration, out _);
|
||||
|
||||
public void Dispose() => SerilogLog.DisposeIfDisposable();
|
||||
public void Dispose() => (SerilogLog as IDisposable)?.Dispose();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a logger with some pre-defined configuration and remainder from config file
|
||||
|
||||
@@ -123,7 +123,7 @@ internal static class UserFactory
|
||||
|
||||
if (entity.HasIdentity)
|
||||
{
|
||||
dto.Id = entity.Id.SafeCast<int>();
|
||||
dto.Id = entity.Id;
|
||||
}
|
||||
|
||||
return dto;
|
||||
|
||||
@@ -675,28 +675,6 @@ public static class FriendlyPublishedContentExtensions
|
||||
public static string Url(this IPublishedContent content, string? culture = null, UrlMode mode = UrlMode.Default)
|
||||
=> content.Url(PublishedUrlProvider, culture, mode);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the children of the content in a DataTable.
|
||||
/// </summary>
|
||||
/// <param name="content">The content.</param>
|
||||
/// <param name="contentTypeAliasFilter">An optional content type alias.</param>
|
||||
/// <param name="culture">
|
||||
/// The specific culture to filter for. If null is used the current culture is used. (Default is
|
||||
/// null)
|
||||
/// </param>
|
||||
/// <returns>The children of the content.</returns>
|
||||
[Obsolete("This method is no longer used in Umbraco. The method will be removed in Umbraco 17.")]
|
||||
public static DataTable ChildrenAsTable(this IPublishedContent content, string contentTypeAliasFilter = "", string? culture = null)
|
||||
=> content.ChildrenAsTable(
|
||||
GetNavigationQueryService(content),
|
||||
GetPublishedStatusFilteringService(content),
|
||||
ContentTypeService,
|
||||
MediaTypeService,
|
||||
MemberTypeService,
|
||||
PublishedUrlProvider,
|
||||
contentTypeAliasFilter,
|
||||
culture);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the url for a media.
|
||||
/// </summary>
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net;
|
||||
using System.Web;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Web.Common.Constants;
|
||||
@@ -65,14 +66,7 @@ public class EncryptionHelper
|
||||
string? additionalRouteValsAsQuery;
|
||||
if (additionalRouteVals != null)
|
||||
{
|
||||
if (additionalRouteVals is Dictionary<string, object> additionalRouteValsAsDictionary)
|
||||
{
|
||||
additionalRouteValsAsQuery = additionalRouteValsAsDictionary.ToQueryString();
|
||||
}
|
||||
else
|
||||
{
|
||||
additionalRouteValsAsQuery = additionalRouteVals.ToDictionary<object>().ToQueryString();
|
||||
}
|
||||
additionalRouteValsAsQuery = new RouteValueDictionary(additionalRouteVals).ToQueryString();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -88,7 +88,7 @@ public abstract class UmbracoIntegrationTest : UmbracoIntegrationTestBase
|
||||
public void TearDownAsync()
|
||||
{
|
||||
_host.StopAsync();
|
||||
Services.DisposeIfDisposable();
|
||||
(Services as IDisposable)?.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -43,7 +43,7 @@ internal sealed class BackOfficeExamineSearcherTests : ExamineBaseTest
|
||||
// When disposing examine, it does a final write, which ends up locking the file if the indexing is not done yet. So we have this wait to circumvent that.
|
||||
Thread.Sleep(1500);
|
||||
// Sometimes we do not dispose all services in time and the test fails because the log file is locked. Resulting in all other tests failing as well
|
||||
Services.DisposeIfDisposable();
|
||||
(Services as IDisposable)?.Dispose();
|
||||
}
|
||||
|
||||
private IDocumentUrlService DocumentUrlService => GetRequiredService<IDocumentUrlService>();
|
||||
|
||||
@@ -47,7 +47,7 @@ internal sealed class ExamineExternalIndexTests : ExamineBaseTest
|
||||
// When disposing examine, it does a final write, which ends up locking the file if the indexing is not done yet. So we have this wait to circumvent that.
|
||||
Thread.Sleep(1500);
|
||||
// Sometimes we do not dispose all services in time and the test fails because the log file is locked. Resulting in all other tests failing as well
|
||||
Services.DisposeIfDisposable();
|
||||
(Services as IDisposable)?.Dispose();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -40,24 +40,6 @@ public class ObjectExtensionsTests
|
||||
Assert.AreEqual(3, result.Result.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ObjectExtensions_Object_To_Dictionary()
|
||||
{
|
||||
// Arrange
|
||||
var obj = new { Key1 = "value1", Key2 = "value2", Key3 = "value3" };
|
||||
|
||||
// Act
|
||||
var d = obj.ToDictionary<string>();
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(d.Keys.Contains("Key1"));
|
||||
Assert.IsTrue(d.Keys.Contains("Key2"));
|
||||
Assert.IsTrue(d.Keys.Contains("Key3"));
|
||||
Assert.AreEqual(d["Key1"], "value1");
|
||||
Assert.AreEqual(d["Key2"], "value2");
|
||||
Assert.AreEqual(d["Key3"], "value3");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanConvertIntToNullableInt()
|
||||
{
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using Lucene.Net.Index;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core;
|
||||
|
||||
[TestFixture]
|
||||
public class DelegateExtensionsTests
|
||||
{
|
||||
[Test]
|
||||
public void Only_Executes_Specific_Count()
|
||||
{
|
||||
const int maxTries = 5;
|
||||
var totalTries = 0;
|
||||
DelegateExtensions.RetryUntilSuccessOrMaxAttempts(
|
||||
currentTry =>
|
||||
{
|
||||
totalTries = currentTry;
|
||||
return Attempt<IndexWriter>.Fail();
|
||||
},
|
||||
5,
|
||||
TimeSpan.FromMilliseconds(10));
|
||||
|
||||
Assert.AreEqual(maxTries, totalTries);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Quits_On_Success_Count()
|
||||
{
|
||||
var totalTries = 0;
|
||||
DelegateExtensions.RetryUntilSuccessOrMaxAttempts(
|
||||
currentTry =>
|
||||
{
|
||||
totalTries = currentTry;
|
||||
return totalTries == 2 ? Attempt<string>.Succeed() : Attempt<string>.Fail();
|
||||
},
|
||||
5,
|
||||
TimeSpan.FromMilliseconds(10));
|
||||
|
||||
Assert.AreEqual(2, totalTries);
|
||||
}
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
// using System.Collections.Generic;
|
||||
// using System.Linq;
|
||||
// using Moq;
|
||||
// using NUnit.Framework;
|
||||
// using Umbraco.Cms.Core.Models;
|
||||
// using Umbraco.Cms.Core.Routing;
|
||||
// using Umbraco.Cms.Core.Services;
|
||||
// using Umbraco.Cms.Infrastructure.PublishedCache;
|
||||
// using Umbraco.Cms.Tests.Common.Builders;
|
||||
// using Umbraco.Cms.Tests.Common.Builders.Extensions;
|
||||
// using Umbraco.Cms.Tests.UnitTests.TestHelpers;
|
||||
// using Umbraco.Extensions;
|
||||
//
|
||||
// namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache;
|
||||
//
|
||||
// FIXME: Reintroduce if relevant
|
||||
// /// <summary>
|
||||
// /// Unit tests for IPublishedContent and extensions
|
||||
// /// </summary>
|
||||
// [TestFixture]
|
||||
// public class PublishedContentDataTableTests : PublishedSnapshotServiceTestBase
|
||||
// {
|
||||
// private readonly DataType[] _dataTypes = GetDefaultDataTypes();
|
||||
//
|
||||
// private static ContentType CreateContentType(string name, IDataType dataType, IReadOnlyDictionary<string, string> propertyAliasesAndNames)
|
||||
// {
|
||||
// var contentType = new ContentType(TestHelper.ShortStringHelper, -1)
|
||||
// {
|
||||
// Alias = name,
|
||||
// Name = name,
|
||||
// Key = Guid.NewGuid(),
|
||||
// Id = name.GetHashCode(),
|
||||
// };
|
||||
// foreach (var prop in propertyAliasesAndNames)
|
||||
// {
|
||||
// contentType.AddPropertyType(new PropertyType(TestHelper.ShortStringHelper, dataType, prop.Key)
|
||||
// {
|
||||
// Name = prop.Value,
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// return contentType;
|
||||
// }
|
||||
//
|
||||
// private IEnumerable<ContentNodeKit> CreateCache(
|
||||
// bool createChildren,
|
||||
// IDataType dataType,
|
||||
// out ContentType[] contentTypes)
|
||||
// {
|
||||
// var result = new List<ContentNodeKit>();
|
||||
// var valueCounter = 1;
|
||||
// var parentId = 3;
|
||||
//
|
||||
// var properties = new Dictionary<string, string> { ["property1"] = "Property 1", ["property2"] = "Property 2" };
|
||||
//
|
||||
// var parentContentType = CreateContentType(
|
||||
// "Parent",
|
||||
// dataType,
|
||||
// new Dictionary<string, string>(properties) { ["property3"] = "Property 3" });
|
||||
// var childContentType = CreateContentType(
|
||||
// "Child",
|
||||
// dataType,
|
||||
// new Dictionary<string, string>(properties) { ["property4"] = "Property 4" });
|
||||
// var child2ContentType = CreateContentType(
|
||||
// "Child2",
|
||||
// dataType,
|
||||
// new Dictionary<string, string>(properties) { ["property4"] = "Property 4" });
|
||||
//
|
||||
// contentTypes = new[] { parentContentType, childContentType, child2ContentType };
|
||||
//
|
||||
// var parentData = new ContentDataBuilder()
|
||||
// .WithName("Page" + Guid.NewGuid())
|
||||
// .WithProperties(new PropertyDataBuilder()
|
||||
// .WithPropertyData("property1", "value" + valueCounter)
|
||||
// .WithPropertyData("property2", "value" + (valueCounter + 1))
|
||||
// .WithPropertyData("property3", "value" + (valueCounter + 2))
|
||||
// .Build())
|
||||
// .Build();
|
||||
//
|
||||
// var parent = ContentNodeKitBuilder.CreateWithContent(
|
||||
// parentContentType.Id,
|
||||
// parentId,
|
||||
// $"-1,{parentId}",
|
||||
// draftData: parentData,
|
||||
// publishedData: parentData);
|
||||
//
|
||||
// result.Add(parent);
|
||||
//
|
||||
// if (createChildren)
|
||||
// {
|
||||
// for (var i = 0; i < 3; i++)
|
||||
// {
|
||||
// valueCounter += 3;
|
||||
// var childId = parentId + i + 1;
|
||||
//
|
||||
// var childData = new ContentDataBuilder()
|
||||
// .WithName("Page" + Guid.NewGuid())
|
||||
// .WithProperties(new PropertyDataBuilder()
|
||||
// .WithPropertyData("property1", "value" + valueCounter)
|
||||
// .WithPropertyData("property2", "value" + (valueCounter + 1))
|
||||
// .WithPropertyData("property4", "value" + (valueCounter + 2))
|
||||
// .Build())
|
||||
// .Build();
|
||||
//
|
||||
// var child = ContentNodeKitBuilder.CreateWithContent(
|
||||
// i > 0 ? childContentType.Id : child2ContentType.Id,
|
||||
// childId,
|
||||
// $"-1,{parentId},{childId}",
|
||||
// i,
|
||||
// draftData: childData,
|
||||
// publishedData: childData);
|
||||
//
|
||||
// result.Add(child);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
// [Test]
|
||||
// public void To_DataTable()
|
||||
// {
|
||||
// var cache = CreateCache(true, _dataTypes[0], out var contentTypes);
|
||||
// InitializedCache(cache, contentTypes, _dataTypes);
|
||||
//
|
||||
// var snapshot = GetPublishedSnapshot();
|
||||
// var root = snapshot.Content.GetAtRoot().First();
|
||||
//
|
||||
// var dt = root.ChildrenAsTable(
|
||||
// VariationContextAccessor,
|
||||
// ContentTypeService,
|
||||
// MediaTypeService,
|
||||
// Mock.Of<IMemberTypeService>(),
|
||||
// Mock.Of<IPublishedUrlProvider>());
|
||||
//
|
||||
// Assert.AreEqual(11, dt.Columns.Count);
|
||||
// Assert.AreEqual(3, dt.Rows.Count);
|
||||
// Assert.AreEqual("value4", dt.Rows[0]["Property 1"]);
|
||||
// Assert.AreEqual("value5", dt.Rows[0]["Property 2"]);
|
||||
// Assert.AreEqual("value6", dt.Rows[0]["Property 4"]);
|
||||
// Assert.AreEqual("value7", dt.Rows[1]["Property 1"]);
|
||||
// Assert.AreEqual("value8", dt.Rows[1]["Property 2"]);
|
||||
// Assert.AreEqual("value9", dt.Rows[1]["Property 4"]);
|
||||
// Assert.AreEqual("value10", dt.Rows[2]["Property 1"]);
|
||||
// Assert.AreEqual("value11", dt.Rows[2]["Property 2"]);
|
||||
// Assert.AreEqual("value12", dt.Rows[2]["Property 4"]);
|
||||
// }
|
||||
//
|
||||
// [Test]
|
||||
// public void To_DataTable_With_Filter()
|
||||
// {
|
||||
// var cache = CreateCache(true, _dataTypes[0], out var contentTypes);
|
||||
// InitializedCache(cache, contentTypes, _dataTypes);
|
||||
//
|
||||
// var snapshot = GetPublishedSnapshot();
|
||||
// var root = snapshot.Content.GetAtRoot().First();
|
||||
//
|
||||
// var dt = root.ChildrenAsTable(
|
||||
// VariationContextAccessor,
|
||||
// ContentTypeService,
|
||||
// MediaTypeService,
|
||||
// Mock.Of<IMemberTypeService>(),
|
||||
// Mock.Of<IPublishedUrlProvider>(),
|
||||
// "Child");
|
||||
//
|
||||
// Assert.AreEqual(11, dt.Columns.Count);
|
||||
// Assert.AreEqual(2, dt.Rows.Count);
|
||||
// Assert.AreEqual("value7", dt.Rows[0]["Property 1"]);
|
||||
// Assert.AreEqual("value8", dt.Rows[0]["Property 2"]);
|
||||
// Assert.AreEqual("value9", dt.Rows[0]["Property 4"]);
|
||||
// Assert.AreEqual("value10", dt.Rows[1]["Property 1"]);
|
||||
// Assert.AreEqual("value11", dt.Rows[1]["Property 2"]);
|
||||
// Assert.AreEqual("value12", dt.Rows[1]["Property 4"]);
|
||||
// }
|
||||
//
|
||||
// [Test]
|
||||
// public void To_DataTable_No_Rows()
|
||||
// {
|
||||
// var cache = CreateCache(false, _dataTypes[0], out var contentTypes);
|
||||
// InitializedCache(cache, contentTypes, _dataTypes);
|
||||
//
|
||||
// var snapshot = GetPublishedSnapshot();
|
||||
// var root = snapshot.Content.GetAtRoot().First();
|
||||
//
|
||||
// var dt = root.ChildrenAsTable(
|
||||
// VariationContextAccessor,
|
||||
// ContentTypeService,
|
||||
// MediaTypeService,
|
||||
// Mock.Of<IMemberTypeService>(),
|
||||
// Mock.Of<IPublishedUrlProvider>());
|
||||
//
|
||||
// // will return an empty data table
|
||||
// Assert.AreEqual(0, dt.Columns.Count);
|
||||
// Assert.AreEqual(0, dt.Rows.Count);
|
||||
// }
|
||||
// }
|
||||
Reference in New Issue
Block a user