Cleanup and fix mappers
This commit is contained in:
@@ -5,8 +5,13 @@ using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Mapping
|
||||
{
|
||||
// FIXME needs documentation and cleanup!
|
||||
// notes:
|
||||
// AutoMapper maps null to empty arrays, lists, etc
|
||||
// AutoMapper maps derived types - we have to be explicit (see DefineAs) - fixme / really?
|
||||
|
||||
/// <summary>
|
||||
/// Umbraco Mapper.
|
||||
/// </summary>
|
||||
public class Mapper
|
||||
{
|
||||
private readonly Dictionary<Type, Dictionary<Type, Func<object, MapperContext, object>>> _ctors
|
||||
@@ -15,6 +20,10 @@ namespace Umbraco.Core.Mapping
|
||||
private readonly Dictionary<Type, Dictionary<Type, Action<object, object, MapperContext>>> _maps
|
||||
= new Dictionary<Type, Dictionary<Type, Action<object, object, MapperContext>>>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Mapper"/> class.
|
||||
/// </summary>
|
||||
/// <param name="profiles"></param>
|
||||
public Mapper(MapperProfileCollection profiles)
|
||||
{
|
||||
foreach (var profile in profiles)
|
||||
@@ -23,14 +32,85 @@ namespace Umbraco.Core.Mapping
|
||||
|
||||
#region Define
|
||||
|
||||
private TTarget ThrowCtor<TSource, TTarget>(TSource source, MapperContext context)
|
||||
=> throw new InvalidOperationException($"Don't know how to create {typeof(TTarget).FullName} instances.");
|
||||
|
||||
private void Identity<TSource, TTarget>(TSource source, TTarget target, MapperContext context)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Defines a mapping.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">The source type.</typeparam>
|
||||
/// <typeparam name="TTarget">The target type.</typeparam>
|
||||
public void Define<TSource, TTarget>()
|
||||
=> Define<TSource, TTarget>((source, target, context) => { });
|
||||
=> Define<TSource, TTarget>(ThrowCtor<TSource, TTarget>, Identity);
|
||||
|
||||
/// <summary>
|
||||
/// Defines a mapping.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">The source type.</typeparam>
|
||||
/// <typeparam name="TTarget">The target type.</typeparam>
|
||||
/// <param name="map">A mapping method.</param>
|
||||
public void Define<TSource, TTarget>(Action<TSource, TTarget, MapperContext> map)
|
||||
=> Define((source, context) => throw new NotSupportedException($"Don't know how to create {typeof(TTarget)} instances."), map);
|
||||
=> Define(ThrowCtor<TSource, TTarget>, map);
|
||||
|
||||
/// <summary>
|
||||
/// Defines a mapping.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">The source type.</typeparam>
|
||||
/// <typeparam name="TTarget">The target type.</typeparam>
|
||||
/// <param name="ctor">A constructor method.</param>
|
||||
public void Define<TSource, TTarget>(Func<TSource, MapperContext, TTarget> ctor)
|
||||
=> Define(ctor, (source, target, context) => { });
|
||||
=> Define(ctor, Identity);
|
||||
|
||||
/// <summary>
|
||||
/// Defines a mapping.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">The source type.</typeparam>
|
||||
/// <typeparam name="TTarget">The target type.</typeparam>
|
||||
/// <param name="ctor">A constructor method.</param>
|
||||
/// <param name="map">A mapping method.</param>
|
||||
public void Define<TSource, TTarget>(Func<TSource, MapperContext, TTarget> ctor, Action<TSource, TTarget, MapperContext> map)
|
||||
{
|
||||
var sourceType = typeof(TSource);
|
||||
var targetType = typeof(TTarget);
|
||||
|
||||
var sourceCtors = DefineCtors(sourceType);
|
||||
if (ctor != null)
|
||||
sourceCtors[targetType] = (source, context) => ctor((TSource)source, context);
|
||||
|
||||
var sourceMaps = DefineMaps(sourceType);
|
||||
sourceMaps[targetType] = (source, target, context) => map((TSource)source, (TTarget)target, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines a mapping as a clone of an already defined mapping.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">The source type.</typeparam>
|
||||
/// <typeparam name="TTarget">The target type.</typeparam>
|
||||
/// <typeparam name="TAsSource">The equivalent source type.</typeparam>
|
||||
/// <typeparam name="TAsTarget">The equivalent target type.</typeparam>
|
||||
public void DefineAs<TSource, TTarget, TAsSource, TAsTarget>()
|
||||
{
|
||||
var sourceType = typeof(TSource);
|
||||
var targetType = typeof(TTarget);
|
||||
|
||||
var asSourceType = typeof(TAsSource);
|
||||
var asTargetType = typeof(TAsTarget);
|
||||
|
||||
var asCtors = DefineCtors(asSourceType);
|
||||
var asMaps = DefineMaps(asSourceType);
|
||||
|
||||
var sourceCtors = DefineCtors(sourceType);
|
||||
var sourceMaps = DefineMaps(sourceType);
|
||||
|
||||
if (!asCtors.TryGetValue(asTargetType, out var ctor) || !asMaps.TryGetValue(asTargetType, out var map))
|
||||
throw new InvalidOperationException($"Don't know hwo to map from {asSourceType.FullName} to {targetType.FullName}.");
|
||||
|
||||
sourceCtors[targetType] = ctor;
|
||||
sourceMaps[targetType] = map;
|
||||
}
|
||||
|
||||
private Dictionary<Type, Func<object, MapperContext, object>> DefineCtors(Type sourceType)
|
||||
{
|
||||
@@ -46,25 +126,26 @@ namespace Umbraco.Core.Mapping
|
||||
return sourceMap;
|
||||
}
|
||||
|
||||
public void Define<TSource, TTarget>(Func<TSource, MapperContext, TTarget> ctor, Action<TSource, TTarget, MapperContext> map)
|
||||
{
|
||||
var sourceType = typeof(TSource);
|
||||
var targetType = typeof(TTarget);
|
||||
|
||||
var sourceCtors = DefineCtors(sourceType);
|
||||
sourceCtors[targetType] = (source, context) => ctor((TSource)source, context);
|
||||
|
||||
var sourceMaps = DefineMaps(sourceType);
|
||||
sourceMaps[targetType] = (source, target, context) => map((TSource)source, (TTarget)target, context);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Map
|
||||
|
||||
/// <summary>
|
||||
/// Maps a source object to a new target object.
|
||||
/// </summary>
|
||||
/// <typeparam name="TTarget">The target type.</typeparam>
|
||||
/// <param name="source">The source object.</param>
|
||||
/// <returns>The target object.</returns>
|
||||
public TTarget Map<TTarget>(object source)
|
||||
=> Map<TTarget>(source, new MapperContext(this));
|
||||
|
||||
/// <summary>
|
||||
/// Maps a source object to a new target object.
|
||||
/// </summary>
|
||||
/// <typeparam name="TTarget">The target type.</typeparam>
|
||||
/// <param name="source">The source object.</param>
|
||||
/// <param name="f">A mapper context preparation method.</param>
|
||||
/// <returns>The target object.</returns>
|
||||
public TTarget Map<TTarget>(object source, Action<MapperContext> f)
|
||||
{
|
||||
var context = new MapperContext(this);
|
||||
@@ -72,16 +153,63 @@ namespace Umbraco.Core.Mapping
|
||||
return Map<TTarget>(source, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a source object to a new target object.
|
||||
/// </summary>
|
||||
/// <typeparam name="TTarget">The target type.</typeparam>
|
||||
/// <param name="source">The source object.</param>
|
||||
/// <param name="context">A mapper context.</param>
|
||||
/// <returns>The target object.</returns>
|
||||
public TTarget Map<TTarget>(object source, MapperContext context)
|
||||
=> Map<TTarget>(source, source?.GetType(), context);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a source object to a new target object.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">The source type.</typeparam>
|
||||
/// <typeparam name="TTarget">The target type.</typeparam>
|
||||
/// <param name="source">The source object.</param>
|
||||
/// <returns>The target object.</returns>
|
||||
public TTarget Map<TSource, TTarget>(TSource source)
|
||||
=> Map<TSource, TTarget>(source, new MapperContext(this));
|
||||
|
||||
/// <summary>
|
||||
/// Maps a source object to a new target object.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">The source type.</typeparam>
|
||||
/// <typeparam name="TTarget">The target type.</typeparam>
|
||||
/// <param name="source">The source object.</param>
|
||||
/// <param name="f">A mapper context preparation method.</param>
|
||||
/// <returns>The target object.</returns>
|
||||
public TTarget Map<TSource, TTarget>(TSource source, Action<MapperContext> f)
|
||||
{
|
||||
var context = new MapperContext(this);
|
||||
f(context);
|
||||
return Map<TSource, TTarget>(source, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a source object to a new target object.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">The source type.</typeparam>
|
||||
/// <typeparam name="TTarget">The target type.</typeparam>
|
||||
/// <param name="source">The source object.</param>
|
||||
/// <param name="context">A mapper context.</param>
|
||||
/// <returns>The target object.</returns>
|
||||
public TTarget Map<TSource, TTarget>(TSource source, MapperContext context)
|
||||
=> Map<TTarget>(source, typeof(TSource), context);
|
||||
|
||||
private TTarget Map<TTarget>(object source, Type sourceType, MapperContext context)
|
||||
{
|
||||
if (source == null)
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
|
||||
var sourceType = source.GetType();
|
||||
var targetType = typeof(TTarget);
|
||||
|
||||
var ctor = GetCtor(sourceType, typeof(TTarget));
|
||||
var map = GetMap(sourceType, typeof(TTarget));
|
||||
var ctor = GetCtor(sourceType, targetType);
|
||||
var map = GetMap(sourceType, targetType);
|
||||
|
||||
// if there is a direct constructor, map
|
||||
if (ctor != null && map != null)
|
||||
{
|
||||
var target = ctor(source, context);
|
||||
@@ -89,36 +217,22 @@ namespace Umbraco.Core.Mapping
|
||||
return (TTarget)target;
|
||||
}
|
||||
|
||||
bool IsOk(Type type)
|
||||
// else, handle enumerable-to-enumerable mapping
|
||||
if (IsGenericOrArray(sourceType) && IsGenericOrArray(targetType))
|
||||
{
|
||||
// note: we're not going to work with just plain enumerables of anything,
|
||||
// only on arrays or anything that is generic and implements IEnumerable<>
|
||||
|
||||
if (type.IsArray && type.GetArrayRank() == 1) return true;
|
||||
if (type.IsGenericType && type.GenericTypeArguments.Length == 1) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Type GetGenericArg(Type type)
|
||||
{
|
||||
if (type.IsArray) return type.GetElementType();
|
||||
if (type.IsGenericType) return type.GenericTypeArguments[0];
|
||||
throw new Exception("panic");
|
||||
}
|
||||
|
||||
if (IsOk(sourceType) && IsOk(targetType))
|
||||
{
|
||||
var sourceGenericArg = GetGenericArg(sourceType);
|
||||
var targetGenericArg = GetGenericArg(targetType);
|
||||
var sourceGenericArg = GetGenericOrArrayArg(sourceType);
|
||||
var targetGenericArg = GetGenericOrArrayArg(targetType);
|
||||
|
||||
var sourceEnumerableType = typeof(IEnumerable<>).MakeGenericType(sourceGenericArg);
|
||||
var targetEnumerableType = typeof(IEnumerable<>).MakeGenericType(targetGenericArg);
|
||||
|
||||
// if both are ienumerable
|
||||
if (sourceEnumerableType.IsAssignableFrom(sourceType) && targetEnumerableType.IsAssignableFrom(targetType))
|
||||
{
|
||||
ctor = GetCtor(sourceGenericArg, targetGenericArg);
|
||||
map = GetMap(sourceGenericArg, targetGenericArg);
|
||||
|
||||
// if there is a constructor for the underlying type, map
|
||||
if (ctor != null && map != null)
|
||||
{
|
||||
var sourceEnumerable = (IEnumerable)source;
|
||||
@@ -139,72 +253,26 @@ namespace Umbraco.Core.Mapping
|
||||
throw new InvalidOperationException($"Don't know how to map {sourceType.FullName} to {targetType.FullName}.");
|
||||
}
|
||||
|
||||
// TODO: when AutoMapper is completely gone these two methods can merge
|
||||
|
||||
public TTarget Map<TSource, TTarget>(TSource source)
|
||||
=> Map<TSource, TTarget>(source, new MapperContext(this));
|
||||
|
||||
public TTarget Map<TSource, TTarget>(TSource source, Action<MapperContext> f)
|
||||
{
|
||||
var context = new MapperContext(this);
|
||||
f(context);
|
||||
return Map<TSource, TTarget>(source, context);
|
||||
}
|
||||
|
||||
public TTarget Map<TSource, TTarget>(TSource source, MapperContext context)
|
||||
{
|
||||
if (source == null)
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
|
||||
var sourceType = typeof(TSource);
|
||||
var targetType = typeof(TTarget);
|
||||
|
||||
var ctor = GetCtor(sourceType, typeof(TTarget));
|
||||
var map = GetMap(sourceType, targetType);
|
||||
if (ctor != null && map != null)
|
||||
{
|
||||
var target = ctor(source, context);
|
||||
map(source, target, context);
|
||||
return (TTarget) target;
|
||||
}
|
||||
|
||||
if (sourceType.IsGenericType && targetType.IsGenericType)
|
||||
{
|
||||
var sourceGeneric = sourceType.GetGenericTypeDefinition();
|
||||
var targetGeneric = targetType.GetGenericTypeDefinition();
|
||||
var ienumerable = typeof(IEnumerable<>);
|
||||
|
||||
if (sourceGeneric == ienumerable && targetGeneric == ienumerable)
|
||||
{
|
||||
var sourceGenericType = sourceType.GenericTypeArguments[0];
|
||||
var targetGenericType = targetType.GenericTypeArguments[0];
|
||||
|
||||
ctor = GetCtor(sourceGenericType, targetGenericType);
|
||||
map = GetMap(sourceGenericType, targetGenericType);
|
||||
|
||||
if (ctor != null && map != null)
|
||||
{
|
||||
var sourceEnumerable = (IEnumerable)source;
|
||||
var targetEnumerable = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(targetGenericType));
|
||||
|
||||
foreach (var sourceItem in sourceEnumerable)
|
||||
{
|
||||
var targetItem = ctor(sourceItem, context);
|
||||
map(sourceItem, targetItem, context);
|
||||
targetEnumerable.Add(targetItem);
|
||||
}
|
||||
|
||||
return (TTarget)targetEnumerable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Don't know how to map {sourceType.FullName} to {targetType.FullName}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a source object to an existing target object.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">The source type.</typeparam>
|
||||
/// <typeparam name="TTarget">The target type.</typeparam>
|
||||
/// <param name="source">The source object.</param>
|
||||
/// <param name="target">The target object.</param>
|
||||
/// <returns>The target object.</returns>
|
||||
public TTarget Map<TSource, TTarget>(TSource source, TTarget target)
|
||||
=> Map(source, target, new MapperContext(this));
|
||||
|
||||
/// <summary>
|
||||
/// Maps a source object to an existing target object.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">The source type.</typeparam>
|
||||
/// <typeparam name="TTarget">The target type.</typeparam>
|
||||
/// <param name="source">The source object.</param>
|
||||
/// <param name="target">The target object.</param>
|
||||
/// <param name="f">A mapper context preparation method.</param>
|
||||
/// <returns>The target object.</returns>
|
||||
public TTarget Map<TSource, TTarget>(TSource source, TTarget target, Action<MapperContext> f)
|
||||
{
|
||||
var context = new MapperContext(this);
|
||||
@@ -212,18 +280,32 @@ namespace Umbraco.Core.Mapping
|
||||
return Map(source, target, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a source object to an existing target object.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">The source type.</typeparam>
|
||||
/// <typeparam name="TTarget">The target type.</typeparam>
|
||||
/// <param name="source">The source object.</param>
|
||||
/// <param name="target">The target object.</param>
|
||||
/// <param name="context">A mapper context.</param>
|
||||
/// <returns>The target object.</returns>
|
||||
public TTarget Map<TSource, TTarget>(TSource source, TTarget target, MapperContext context)
|
||||
{
|
||||
// fixme should we deal with enumerables?
|
||||
var sourceType = typeof(TSource);
|
||||
var targetType = typeof(TTarget);
|
||||
|
||||
var map = GetMap(source.GetType(), typeof(TTarget));
|
||||
if (map == null)
|
||||
var map = GetMap(sourceType, targetType);
|
||||
|
||||
// if there is a direct map, map
|
||||
if (map != null)
|
||||
{
|
||||
throw new InvalidOperationException($"Don't know how to map {typeof(TSource).FullName} to {typeof(TTarget).FullName}.");
|
||||
map(source, target, context);
|
||||
return target;
|
||||
}
|
||||
|
||||
map(source, target, context);
|
||||
return target;
|
||||
// we cannot really map to an existing enumerable - give up
|
||||
|
||||
throw new InvalidOperationException($"Don't know how to map {typeof(TSource).FullName} to {typeof(TTarget).FullName}.");
|
||||
}
|
||||
|
||||
private Func<object, MapperContext, object> GetCtor(Type sourceType, Type targetType)
|
||||
@@ -252,6 +334,23 @@ namespace Umbraco.Core.Mapping
|
||||
return sourceMap.TryGetValue(targetType, out var map) ? map : null;
|
||||
}
|
||||
|
||||
private static bool IsGenericOrArray(Type type)
|
||||
{
|
||||
// note: we're not going to work with just plain enumerables of anything,
|
||||
// only on arrays or anything that is generic and implements IEnumerable<>
|
||||
|
||||
if (type.IsArray && type.GetArrayRank() == 1) return true;
|
||||
if (type.IsGenericType && type.GenericTypeArguments.Length == 1) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Type GetGenericOrArrayArg(Type type)
|
||||
{
|
||||
if (type.IsArray) return type.GetElementType();
|
||||
if (type.IsGenericType) return type.GenericTypeArguments[0];
|
||||
throw new Exception("panic");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,62 +54,46 @@
|
||||
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.CodeAnalysis" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.CodeAnalysis.CSharp" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.2.2.0" newVersion="1.2.2.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.4.2.0" newVersion="1.4.2.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Text.Encoding.CodePages" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.2.3.0" newVersion="1.2.3.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0"/>
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
|
||||
|
||||
@@ -65,11 +65,39 @@ namespace Umbraco.Tests.Mapping
|
||||
//Assert.AreEqual("value", thing2.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InheritedMap()
|
||||
{
|
||||
var profiles = new MapperProfileCollection(new IMapperProfile[]
|
||||
{
|
||||
new Profile1(),
|
||||
});
|
||||
var mapper = new Mapper(profiles);
|
||||
|
||||
var thing3 = new Thing3 { Value = "value" };
|
||||
var thing2 = mapper.Map<Thing3, Thing2>(thing3);
|
||||
|
||||
Assert.IsNotNull(thing2);
|
||||
Assert.AreEqual("value", thing2.Value);
|
||||
|
||||
thing2 = mapper.Map<Thing2>(thing3);
|
||||
|
||||
Assert.IsNotNull(thing2);
|
||||
Assert.AreEqual("value", thing2.Value);
|
||||
|
||||
thing2 = new Thing2();
|
||||
mapper.Map(thing3, thing2);
|
||||
Assert.AreEqual("value", thing2.Value);
|
||||
}
|
||||
|
||||
private class Thing1
|
||||
{
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
||||
private class Thing3 : Thing1
|
||||
{ }
|
||||
|
||||
private class Thing2
|
||||
{
|
||||
public string Value { get; set; }
|
||||
|
||||
@@ -1,198 +0,0 @@
|
||||
using System;
|
||||
using AutoMapper;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Umbraco.Tests.Models.Mapping
|
||||
{
|
||||
[TestFixture]
|
||||
public class AutoMapper6Tests
|
||||
{
|
||||
[Test]
|
||||
public void Test1()
|
||||
{
|
||||
ThingProfile.CtorCount = 0;
|
||||
Assert.AreEqual(0, ThingProfile.CtorCount);
|
||||
|
||||
var config = new MapperConfiguration(cfg =>
|
||||
{
|
||||
cfg.AddProfile<ThingProfile1>();
|
||||
});
|
||||
|
||||
Assert.AreEqual(1, ThingProfile.CtorCount);
|
||||
Assert.AreEqual(0, MemberValueResolver.CtorCount);
|
||||
|
||||
var mapper = config.CreateMapper();
|
||||
|
||||
Assert.AreEqual(1, ThingProfile.CtorCount);
|
||||
Assert.AreEqual(0, MemberValueResolver.CtorCount);
|
||||
|
||||
var thingA = new ThingA { ValueInt = 42, ValueString = "foo" };
|
||||
var thingB = mapper.Map<ThingA, ThingB>(thingA);
|
||||
Assert.AreEqual(42, thingB.ValueInt);
|
||||
Assert.AreEqual("!!foo!!", thingB.ValueString);
|
||||
|
||||
mapper.Map<ThingA, ThingB>(thingA);
|
||||
mapper.Map<ThingA, ThingB>(thingA);
|
||||
mapper.Map<ThingA, ThingB>(thingA);
|
||||
Assert.AreEqual(1, ThingProfile.CtorCount); // one single profile
|
||||
Assert.AreEqual(4, MemberValueResolver.CtorCount); // many resolvers
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test2()
|
||||
{
|
||||
var config = new MapperConfiguration(cfg =>
|
||||
{
|
||||
cfg.AddProfile<ThingProfile2>();
|
||||
});
|
||||
|
||||
var mapper = config.CreateMapper();
|
||||
|
||||
Assert.AreEqual(0, ValueResolver.CtorCount);
|
||||
|
||||
var thingA = new ThingA { ValueInt = 42, ValueString = "foo" };
|
||||
var thingB = mapper.Map<ThingA, ThingB>(thingA);
|
||||
Assert.AreEqual(42, thingB.ValueInt);
|
||||
Assert.AreEqual("!!foo!!", thingB.ValueString);
|
||||
|
||||
mapper.Map<ThingA, ThingB>(thingA);
|
||||
mapper.Map<ThingA, ThingB>(thingA);
|
||||
mapper.Map<ThingA, ThingB>(thingA);
|
||||
Assert.AreEqual(4, ValueResolver.CtorCount); // many resolvers
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test3()
|
||||
{
|
||||
var config = new MapperConfiguration(cfg =>
|
||||
{
|
||||
cfg.AddProfile<ThingProfile3>();
|
||||
});
|
||||
|
||||
var mapper = config.CreateMapper();
|
||||
|
||||
var thingA = new ThingA { ValueInt = 42, ValueString = "foo" };
|
||||
var thingB = mapper.Map<ThingA, ThingB>(thingA);
|
||||
Assert.AreEqual(42, thingB.ValueInt);
|
||||
Assert.AreEqual("!!foo!!", thingB.ValueString);
|
||||
|
||||
mapper.Map<ThingA, ThingB>(thingA);
|
||||
mapper.Map<ThingA, ThingB>(thingA);
|
||||
mapper.Map<ThingA, ThingB>(thingA);
|
||||
}
|
||||
|
||||
// Resolve destination member using a custom value resolver
|
||||
// void ResolveUsing<TValueResolver>()
|
||||
// where TValueResolver : IValueResolver<TSource, TDestination, TDestMember>;
|
||||
|
||||
// Resolve destination member using a custom value resolver from a source member
|
||||
// void ResolveUsing<TValueResolver, TSourceMember>(Expression<Func<TSource, TSourceMember>> sourceMember)
|
||||
// where TValueResolver : IMemberValueResolver<TSource, TDestination, TSourceMember, TMember>;
|
||||
// void ResolveUsing<TValueResolver, TSourceMember>(string sourceMemberName)
|
||||
// where TValueResolver : IMemberValueResolver<TSource, TDestination, TSourceMember, TMember>;
|
||||
|
||||
// Resolve destination member using a custom value resolver instance
|
||||
// void ResolveUsing(IValueResolver<TSource, TDestination, TMember> valueResolver);
|
||||
// void ResolveUsing<TSourceMember>(IMemberValueResolver<TSource, TDestination, TSourceMember, TMember> valueResolver, Expression<Func<TSource, TSourceMember>> sourceMember);
|
||||
|
||||
// Resolve destination member using a custom value resolver callback
|
||||
// void ResolveUsing<TResult>(Func<TSource, TResult> resolver);
|
||||
// void ResolveUsing<TResult>(Func<TSource, TDestination, TResult> resolver);
|
||||
// void ResolveUsing<TResult>(Func<TSource, TDestination, TMember, TResult> resolver);
|
||||
// void ResolveUsing<TResult>(Func<TSource, TDestination, TMember, ResolutionContext, TResult> resolver);
|
||||
|
||||
// read https://stackoverflow.com/questions/14875075/automapper-what-is-the-difference-between-mapfrom-and-resolveusing
|
||||
// about the diff between MapFrom and ResolveUsing... keeping ResolveUsing in our code
|
||||
|
||||
public class ThingProfile : Profile
|
||||
{
|
||||
public static int CtorCount { get; set; }
|
||||
|
||||
public ThingProfile(int ver)
|
||||
{
|
||||
CtorCount++;
|
||||
|
||||
var map = CreateMap<ThingA, ThingB>()
|
||||
.ForMember(dest => dest.ValueInt, opt => opt.MapFrom(src => src.ValueInt));
|
||||
|
||||
switch (ver)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
map
|
||||
.ForMember(dest => dest.ValueString, opt => opt.MapFrom<MemberValueResolver, string>(src => src.ValueString));
|
||||
break;
|
||||
case 2:
|
||||
map
|
||||
.ForMember(dest => dest.ValueString, opt => opt.MapFrom<ValueResolver>());
|
||||
break;
|
||||
case 3:
|
||||
// in most cases that should be perfectly enough?
|
||||
map
|
||||
.ForMember(dest => dest.ValueString, opt => opt.MapFrom(source => "!!" + source.ValueString + "!!"));
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(ver));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ThingProfile1 : ThingProfile
|
||||
{
|
||||
public ThingProfile1() : base(1) { }
|
||||
}
|
||||
|
||||
public class ThingProfile2 : ThingProfile
|
||||
{
|
||||
public ThingProfile2() : base(2) { }
|
||||
}
|
||||
|
||||
public class ThingProfile3 : ThingProfile
|
||||
{
|
||||
public ThingProfile3() : base(3) { }
|
||||
}
|
||||
|
||||
public class ValueResolver : IValueResolver<ThingA, ThingB, string>
|
||||
{
|
||||
public static int CtorCount { get; set; }
|
||||
|
||||
public ValueResolver()
|
||||
{
|
||||
CtorCount++;
|
||||
}
|
||||
|
||||
public string Resolve(ThingA source, ThingB destination, string destMember, ResolutionContext context)
|
||||
{
|
||||
return "!!" + source.ValueString + "!!";
|
||||
}
|
||||
}
|
||||
|
||||
public class MemberValueResolver : IMemberValueResolver<ThingA, ThingB, string, string>
|
||||
{
|
||||
public static int CtorCount { get; set; }
|
||||
|
||||
public MemberValueResolver()
|
||||
{
|
||||
CtorCount++;
|
||||
}
|
||||
|
||||
public string Resolve(ThingA source, ThingB destination, string sourceMember, string destMember, ResolutionContext context)
|
||||
{
|
||||
return "!!" + sourceMember + "!!";
|
||||
}
|
||||
}
|
||||
|
||||
public class ThingA
|
||||
{
|
||||
public int ValueInt { get; set; }
|
||||
public string ValueString { get; set; }
|
||||
}
|
||||
|
||||
public class ThingB
|
||||
{
|
||||
public int ValueInt { get; set; }
|
||||
public string ValueString { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.Testing;
|
||||
|
||||
namespace Umbraco.Tests.Models.Mapping
|
||||
{
|
||||
[TestFixture]
|
||||
[UmbracoTest(WithApplication = true)]
|
||||
public class AutoMapperTests : UmbracoTestBase
|
||||
{
|
||||
protected override void Compose()
|
||||
{
|
||||
base.Compose();
|
||||
|
||||
var manifestBuilder = new ManifestParser(
|
||||
AppCaches.Disabled,
|
||||
new ManifestValueValidatorCollection(Enumerable.Empty<IManifestValueValidator>()),
|
||||
Composition.Logger)
|
||||
{
|
||||
Path = TestHelper.CurrentAssemblyDirectory
|
||||
};
|
||||
Composition.RegisterUnique(_ => manifestBuilder);
|
||||
|
||||
Func<IEnumerable<Type>> typeListProducerList = Enumerable.Empty<Type>;
|
||||
Composition.WithCollectionBuilder<DataEditorCollectionBuilder>()
|
||||
.Clear()
|
||||
.Add(typeListProducerList);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AssertConfigurationIsValid()
|
||||
{
|
||||
var profiles = Factory.GetAllInstances<Profile>().ToArray();
|
||||
|
||||
var config = new MapperConfiguration(cfg =>
|
||||
{
|
||||
foreach (var profile in profiles)
|
||||
cfg.AddProfile(profile);
|
||||
});
|
||||
|
||||
// validate each profile (better granularity for error reports)
|
||||
|
||||
Console.WriteLine("Validate each profile:");
|
||||
foreach (var profile in profiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
config.AssertConfigurationIsValid(profile.GetType().FullName);
|
||||
//Console.WriteLine("OK " + profile.GetType().FullName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("KO " + profile.GetType().FullName);
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Validate each profile and throw:");
|
||||
foreach (var profile in profiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
config.AssertConfigurationIsValid(profile.GetType().FullName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("KO " + profile.GetType().FullName);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// validate the global config
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Validate global config:");
|
||||
config.AssertConfigurationIsValid();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
@@ -11,7 +10,6 @@ using Umbraco.Core.Services;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Models.Mapping;
|
||||
using Umbraco.Web.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Tests.Models.Mapping
|
||||
@@ -28,22 +26,6 @@ namespace Umbraco.Tests.Models.Mapping
|
||||
private readonly Mock<IFileService> _fileService = new Mock<IFileService>();
|
||||
private Mock<PropertyEditorCollection> _editorsMock;
|
||||
|
||||
public override void SetUp()
|
||||
{
|
||||
base.SetUp();
|
||||
|
||||
// FIXME: are we initializing mappers that... have already been?
|
||||
Mapper.Reset();
|
||||
Mapper.Initialize(configuration =>
|
||||
{
|
||||
//initialize our content type mapper
|
||||
var profile1 = new ContentTypeMapperProfile(_editorsMock.Object, _dataTypeService.Object, _fileService.Object, _contentTypeService.Object, Mock.Of<IMediaTypeService>(), Mock.Of<ILogger>());
|
||||
configuration.AddProfile(profile1);
|
||||
var profile2 = new EntityMapperProfile();
|
||||
configuration.AddProfile(profile2);
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Compose()
|
||||
{
|
||||
base.Compose();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
@@ -22,7 +21,7 @@ using Current = Umbraco.Web.Composing.Current;
|
||||
namespace Umbraco.Tests.Models.Mapping
|
||||
{
|
||||
[TestFixture]
|
||||
[UmbracoTest(AutoMapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
|
||||
[UmbracoTest(Mapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
|
||||
public class ContentWebModelMappingTests : TestWithDatabaseBase
|
||||
{
|
||||
private IContentTypeService _contentTypeService;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using AutoMapper;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
@@ -10,7 +9,7 @@ using Umbraco.Web.Models.ContentEditing;
|
||||
namespace Umbraco.Tests.Models.Mapping
|
||||
{
|
||||
[TestFixture]
|
||||
[UmbracoTest(AutoMapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
|
||||
[UmbracoTest(Mapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
|
||||
public class UserModelMapperTests : TestWithDatabaseBase
|
||||
{
|
||||
[Test]
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
@@ -20,7 +17,7 @@ using Umbraco.Web.Models.ContentEditing;
|
||||
namespace Umbraco.Tests.Persistence.Repositories
|
||||
{
|
||||
[TestFixture]
|
||||
[UmbracoTest(AutoMapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
[UmbracoTest(Mapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class ContentTypeRepositoryTest : TestWithDatabaseBase
|
||||
{
|
||||
public override void SetUp()
|
||||
|
||||
@@ -12,17 +12,17 @@ namespace Umbraco.Tests.Testing
|
||||
/// <remarks>
|
||||
/// <para>Default is false.</para>
|
||||
/// <para>This is for tests that inherited from TestWithApplicationBase.</para>
|
||||
/// <para>Implies AutoMapper = true (, ResetPluginManager = false).</para>
|
||||
/// <para>Implies Mapper = true (, ResetPluginManager = false).</para>
|
||||
/// </remarks>
|
||||
public bool WithApplication { get => _withApplication.ValueOrDefault(false); set => _withApplication.Set(value); }
|
||||
private readonly Settable<bool> _withApplication = new Settable<bool>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to compose and initialize AutoMapper.
|
||||
/// Gets or sets a value indicating whether to compose and initialize the mapper.
|
||||
/// </summary>
|
||||
/// <remarks>Default is false unless WithApplication is true, in which case default is true.</remarks>
|
||||
public bool AutoMapper { get => _autoMapper.ValueOrDefault(WithApplication); set => _autoMapper.Set(value); }
|
||||
private readonly Settable<bool> _autoMapper = new Settable<bool>();
|
||||
public bool Mapper { get => _mapper.ValueOrDefault(WithApplication); set => _mapper.Set(value); }
|
||||
private readonly Settable<bool> _mapper = new Settable<bool>();
|
||||
|
||||
// FIXME: to be completed
|
||||
/// <summary>
|
||||
@@ -59,7 +59,7 @@ namespace Umbraco.Tests.Testing
|
||||
|
||||
base.Merge(other);
|
||||
|
||||
_autoMapper.Set(attr._autoMapper);
|
||||
_mapper.Set(attr._mapper);
|
||||
_publishedRepositoryEvents.Set(attr._publishedRepositoryEvents);
|
||||
_logger.Set(attr._logger);
|
||||
_database.Set(attr._database);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using AutoMapper;
|
||||
using Examine;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
@@ -37,6 +36,7 @@ using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web.Trees;
|
||||
using Umbraco.Core.Composing.CompositionExtensions;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Web.Composing.CompositionExtensions;
|
||||
using Umbraco.Web.Sections;
|
||||
using Current = Umbraco.Core.Composing.Current;
|
||||
@@ -108,6 +108,8 @@ namespace Umbraco.Tests.Testing
|
||||
|
||||
protected IMapperCollection Mappers => Factory.GetInstance<IMapperCollection>();
|
||||
|
||||
protected Mapper Mapper => Factory.GetInstance<Mapper>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Setup
|
||||
@@ -148,7 +150,7 @@ namespace Umbraco.Tests.Testing
|
||||
|
||||
protected virtual void Compose()
|
||||
{
|
||||
ComposeAutoMapper(Options.AutoMapper);
|
||||
ComposeMapper(Options.Mapper);
|
||||
ComposeDatabase(Options.Database);
|
||||
ComposeApplication(Options.WithApplication);
|
||||
|
||||
@@ -165,7 +167,6 @@ namespace Umbraco.Tests.Testing
|
||||
|
||||
protected virtual void Initialize()
|
||||
{
|
||||
InitializeAutoMapper(Options.AutoMapper);
|
||||
InitializeApplication(Options.WithApplication);
|
||||
}
|
||||
|
||||
@@ -249,7 +250,7 @@ namespace Umbraco.Tests.Testing
|
||||
Composition.WithCollectionBuilder<ContentAppFactoryCollectionBuilder>();
|
||||
}
|
||||
|
||||
protected virtual void ComposeAutoMapper(bool configure)
|
||||
protected virtual void ComposeMapper(bool configure)
|
||||
{
|
||||
if (configure == false) return;
|
||||
|
||||
@@ -371,18 +372,6 @@ namespace Umbraco.Tests.Testing
|
||||
|
||||
#region Initialize
|
||||
|
||||
protected virtual void InitializeAutoMapper(bool configure)
|
||||
{
|
||||
if (configure == false) return;
|
||||
|
||||
Mapper.Initialize(configuration =>
|
||||
{
|
||||
var profiles = Factory.GetAllInstances<Profile>();
|
||||
foreach (var profile in profiles)
|
||||
configuration.AddProfile(profile);
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual void InitializeApplication(bool withApplication)
|
||||
{
|
||||
if (withApplication == false) return;
|
||||
@@ -430,8 +419,6 @@ namespace Umbraco.Tests.Testing
|
||||
UriUtility.ResetAppDomainAppVirtualPath();
|
||||
SettingsForTests.Reset(); // FIXME: should it be optional?
|
||||
|
||||
Mapper.Reset();
|
||||
|
||||
// clear static events
|
||||
DocumentRepository.ClearScopeEvents();
|
||||
MediaRepository.ClearScopeEvents();
|
||||
|
||||
@@ -163,7 +163,6 @@
|
||||
<Compile Include="Issues\U9560.cs" />
|
||||
<Compile Include="Integration\ContentEventsTests.cs" />
|
||||
<Compile Include="Migrations\AdvancedMigrationTests.cs" />
|
||||
<Compile Include="Models\Mapping\AutoMapper6Tests.cs" />
|
||||
<Compile Include="Models\Mapping\UserModelMapperTests.cs" />
|
||||
<Compile Include="Packaging\PackageExtractionTests.cs" />
|
||||
<Compile Include="Persistence\NPocoTests\NPocoFetchTests.cs" />
|
||||
@@ -271,7 +270,6 @@
|
||||
<Compile Include="Migrations\Stubs\SixZeroMigration2.cs" />
|
||||
<Compile Include="Testing\TestingTests\MockTests.cs" />
|
||||
<Compile Include="Models\MacroTests.cs" />
|
||||
<Compile Include="Models\Mapping\AutoMapperTests.cs" />
|
||||
<Compile Include="Models\Collections\Item.cs" />
|
||||
<Compile Include="Models\Collections\OrderItem.cs" />
|
||||
<Compile Include="Models\Collections\SimpleOrder.cs" />
|
||||
|
||||
@@ -3,8 +3,8 @@ using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Web.Http.Controllers;
|
||||
using System.Web.Http.Filters;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
@@ -27,6 +27,8 @@ namespace Umbraco.Web.Editors.Filters
|
||||
_userService = userService;
|
||||
}
|
||||
|
||||
private static Mapper Mapper => Current.Mapper;
|
||||
|
||||
private IUserService UserService => _userService ?? Current.Services.UserService; // TODO: inject
|
||||
|
||||
public override void OnActionExecuting(HttpActionContext actionContext)
|
||||
|
||||
101
src/Umbraco.Web/Models/Mapping/CommonMapper.cs
Normal file
101
src/Umbraco.Web/Models/Mapping/CommonMapper.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.ContentEditing;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.ContentApps;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Trees;
|
||||
using UserProfile = Umbraco.Web.Models.ContentEditing.UserProfile;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
internal class CommonMapper
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider;
|
||||
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
|
||||
private readonly ContentAppFactoryCollection _contentAppDefinitions;
|
||||
private readonly ILocalizedTextService _localizedTextService;
|
||||
|
||||
public CommonMapper(IUserService userService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IUmbracoContextAccessor umbracoContextAccessor,
|
||||
ContentAppFactoryCollection contentAppDefinitions, ILocalizedTextService localizedTextService)
|
||||
{
|
||||
_userService = userService;
|
||||
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
_contentAppDefinitions = contentAppDefinitions;
|
||||
_localizedTextService = localizedTextService;
|
||||
}
|
||||
|
||||
public UserProfile GetOwner(IContentBase source, Mapper mapper)
|
||||
{
|
||||
var profile = source.GetCreatorProfile(_userService);
|
||||
return profile == null ? null : mapper.Map<IProfile, UserProfile>(profile);
|
||||
}
|
||||
|
||||
public UserProfile GetCreator(IContent source, Mapper mapper)
|
||||
{
|
||||
var profile = source.GetWriterProfile(_userService);
|
||||
return profile == null ? null : mapper.Map<IProfile, UserProfile>(profile);
|
||||
}
|
||||
|
||||
public ContentTypeBasic GetContentType(IContentBase source, Mapper mapper)
|
||||
{
|
||||
// TODO: We can resolve the UmbracoContext from the IValueResolver options!
|
||||
// OMG
|
||||
if (HttpContext.Current != null && Composing.Current.UmbracoContext != null && Composing.Current.UmbracoContext.Security.CurrentUser != null
|
||||
&& Composing.Current.UmbracoContext.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
|
||||
{
|
||||
var contentType = _contentTypeBaseServiceProvider.GetContentTypeOf(source);
|
||||
var contentTypeBasic = mapper.Map<IContentTypeComposition, ContentTypeBasic>(contentType);
|
||||
|
||||
return contentTypeBasic;
|
||||
}
|
||||
//no access
|
||||
return null;
|
||||
}
|
||||
|
||||
public string GetTreeNodeUrl<TController>(IContentBase source)
|
||||
where TController : ContentTreeControllerBase
|
||||
{
|
||||
var umbracoContext = _umbracoContextAccessor.UmbracoContext;
|
||||
if (umbracoContext == null) return null;
|
||||
|
||||
var urlHelper = new UrlHelper(umbracoContext.HttpContext.Request.RequestContext);
|
||||
return urlHelper.GetUmbracoApiService<TController>(controller => controller.GetTreeNode(source.Key.ToString("N"), null));
|
||||
}
|
||||
|
||||
public string GetMemberTreeNodeUrl(IContentBase source)
|
||||
{
|
||||
var umbracoContext = _umbracoContextAccessor.UmbracoContext;
|
||||
if (umbracoContext == null) return null;
|
||||
|
||||
var urlHelper = new UrlHelper(umbracoContext.HttpContext.Request.RequestContext);
|
||||
return urlHelper.GetUmbracoApiService<MemberTreeController>(controller => controller.GetTreeNode(source.Key.ToString("N"), null));
|
||||
}
|
||||
|
||||
public IEnumerable<ContentApp> GetContentApps(IContentBase source)
|
||||
{
|
||||
var apps = _contentAppDefinitions.GetContentAppsFor(source).ToArray();
|
||||
|
||||
// localize content app names
|
||||
foreach (var app in apps)
|
||||
{
|
||||
var localizedAppName = _localizedTextService.Localize($"apps/{app.Alias}");
|
||||
if (localizedAppName.Equals($"[{app.Alias}]", StringComparison.OrdinalIgnoreCase) == false)
|
||||
{
|
||||
app.Name = localizedAppName;
|
||||
}
|
||||
}
|
||||
|
||||
return apps;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,11 +55,18 @@ namespace Umbraco.Web.Models.Mapping
|
||||
|
||||
public void SetMaps(Mapper mapper)
|
||||
{
|
||||
mapper.Define<IContent, ContentPropertyCollectionDto>((source, context) => new ContentPropertyCollectionDto(), Map);
|
||||
mapper.Define<IContent, ContentItemDisplay>((source, context) => new ContentItemDisplay(), Map);
|
||||
mapper.Define<IContent, ContentVariantDisplay>((source, context) => new ContentVariantDisplay(), Map);
|
||||
mapper.Define<IContent, ContentItemBasic<ContentPropertyBasic>>((source, context) => new ContentItemBasic<ContentPropertyBasic>(), Map);
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(IContent source, ContentPropertyCollectionDto target, MapperContext context)
|
||||
{
|
||||
target.Properties = source.Properties.Select(context.Mapper.Map<ContentPropertyDto>);
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll -AllowPreview -Errors -PersistedContent
|
||||
private void Map(IContent source, ContentItemDisplay target, MapperContext context)
|
||||
{
|
||||
@@ -120,7 +127,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
target.Owner = _commonMapper.GetOwner(source, context.Mapper);
|
||||
target.ParentId = source.ParentId;
|
||||
target.Path = source.Path;
|
||||
target.Properties = context.Mapper.Map<IEnumerable<ContentPropertyBasic>>(source.Properties);
|
||||
target.Properties = source.Properties.Select(context.Mapper.Map<ContentPropertyBasic>);
|
||||
target.SortOrder = source.SortOrder;
|
||||
target.State = _basicStateMapper.Map(source, context);
|
||||
target.Trashed = source.Trashed;
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
/// Assigns the PropertyEditor, Id, Alias and Value to the property
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual TDestination Map(Property property, TDestination dest, MapperContext context)
|
||||
public virtual void Map(Property property, TDestination dest, MapperContext context)
|
||||
{
|
||||
var editor = _propertyEditors[property.PropertyType.PropertyEditorAlias];
|
||||
if (editor == null)
|
||||
@@ -44,19 +44,16 @@ namespace Umbraco.Web.Models.Mapping
|
||||
editor = _propertyEditors[Constants.PropertyEditors.Aliases.Label];
|
||||
}
|
||||
|
||||
var result = new TDestination
|
||||
{
|
||||
Id = property.Id,
|
||||
Alias = property.Alias,
|
||||
PropertyEditor = editor,
|
||||
Editor = editor.Alias
|
||||
};
|
||||
dest.Id = property.Id;
|
||||
dest.Alias = property.Alias;
|
||||
dest.PropertyEditor = editor;
|
||||
dest.Editor = editor.Alias;
|
||||
|
||||
// if there's a set of property aliases specified, we will check if the current property's value should be mapped.
|
||||
// if it isn't one of the ones specified in 'includeProperties', we will just return the result without mapping the Value.
|
||||
var includedProperties = context.GetIncludedProperties();
|
||||
if (includedProperties != null && !includedProperties.Contains(property.Alias))
|
||||
return result;
|
||||
return;
|
||||
|
||||
//Get the culture from the context which will be set during the mapping operation for each property
|
||||
var culture = context.GetCulture();
|
||||
@@ -68,11 +65,10 @@ namespace Umbraco.Web.Models.Mapping
|
||||
//set the culture to null if it's an invariant property type
|
||||
culture = !property.PropertyType.VariesByCulture() ? null : culture;
|
||||
|
||||
result.Culture = culture;
|
||||
dest.Culture = culture;
|
||||
|
||||
// if no 'IncludeProperties' were specified or this property is set to be included - we will map the value and return.
|
||||
result.Value = editor.GetValueEditor().ToEditor(property, DataTypeService, culture);
|
||||
return result;
|
||||
dest.Value = editor.GetValueEditor().ToEditor(property, DataTypeService, culture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
_textService = textService;
|
||||
}
|
||||
public override ContentPropertyDisplay Map(Property originalProp, ContentPropertyDisplay dest, MapperContext context)
|
||||
public override void Map(Property originalProp, ContentPropertyDisplay dest, MapperContext context)
|
||||
{
|
||||
var display = base.Map(originalProp, dest, context);
|
||||
base.Map(originalProp, dest, context);
|
||||
|
||||
var config = DataTypeService.GetDataType(originalProp.PropertyType.DataTypeId).Configuration;
|
||||
|
||||
@@ -32,37 +32,35 @@ namespace Umbraco.Web.Models.Mapping
|
||||
// - does it make any sense to use a IDataValueEditor without configuring it?
|
||||
|
||||
// configure the editor for display with configuration
|
||||
var valEditor = display.PropertyEditor.GetValueEditor(config);
|
||||
var valEditor = dest.PropertyEditor.GetValueEditor(config);
|
||||
|
||||
//set the display properties after mapping
|
||||
display.Alias = originalProp.Alias;
|
||||
display.Description = originalProp.PropertyType.Description;
|
||||
display.Label = originalProp.PropertyType.Name;
|
||||
display.HideLabel = valEditor.HideLabel;
|
||||
dest.Alias = originalProp.Alias;
|
||||
dest.Description = originalProp.PropertyType.Description;
|
||||
dest.Label = originalProp.PropertyType.Name;
|
||||
dest.HideLabel = valEditor.HideLabel;
|
||||
|
||||
//add the validation information
|
||||
display.Validation.Mandatory = originalProp.PropertyType.Mandatory;
|
||||
display.Validation.Pattern = originalProp.PropertyType.ValidationRegExp;
|
||||
dest.Validation.Mandatory = originalProp.PropertyType.Mandatory;
|
||||
dest.Validation.Pattern = originalProp.PropertyType.ValidationRegExp;
|
||||
|
||||
if (display.PropertyEditor == null)
|
||||
if (dest.PropertyEditor == null)
|
||||
{
|
||||
//display.Config = PreValueCollection.AsDictionary(preVals);
|
||||
//if there is no property editor it means that it is a legacy data type
|
||||
// we cannot support editing with that so we'll just render the readonly value view.
|
||||
display.View = "views/propertyeditors/readonlyvalue/readonlyvalue.html";
|
||||
dest.View = "views/propertyeditors/readonlyvalue/readonlyvalue.html";
|
||||
}
|
||||
else
|
||||
{
|
||||
//let the property editor format the pre-values
|
||||
display.Config = display.PropertyEditor.GetConfigurationEditor().ToValueEditor(config);
|
||||
display.View = valEditor.View;
|
||||
dest.Config = dest.PropertyEditor.GetConfigurationEditor().ToValueEditor(config);
|
||||
dest.View = valEditor.View;
|
||||
}
|
||||
|
||||
//Translate
|
||||
display.Label = _textService.UmbracoDictionaryTranslate(display.Label);
|
||||
display.Description = _textService.UmbracoDictionaryTranslate(display.Description);
|
||||
|
||||
return display;
|
||||
dest.Label = _textService.UmbracoDictionaryTranslate(dest.Label);
|
||||
dest.Description = _textService.UmbracoDictionaryTranslate(dest.Description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,17 +16,15 @@ namespace Umbraco.Web.Models.Mapping
|
||||
: base(dataTypeService, logger, propertyEditors)
|
||||
{ }
|
||||
|
||||
public override ContentPropertyDto Map(Property property, ContentPropertyDto dest, MapperContext context)
|
||||
public override void Map(Property property, ContentPropertyDto dest, MapperContext context)
|
||||
{
|
||||
var propertyDto = base.Map(property, dest, context);
|
||||
base.Map(property, dest, context);
|
||||
|
||||
propertyDto.IsRequired = property.PropertyType.Mandatory;
|
||||
propertyDto.ValidationRegExp = property.PropertyType.ValidationRegExp;
|
||||
propertyDto.Description = property.PropertyType.Description;
|
||||
propertyDto.Label = property.PropertyType.Name;
|
||||
propertyDto.DataType = DataTypeService.GetDataType(property.PropertyType.DataTypeId);
|
||||
|
||||
return propertyDto;
|
||||
dest.IsRequired = property.PropertyType.Mandatory;
|
||||
dest.ValidationRegExp = property.PropertyType.ValidationRegExp;
|
||||
dest.Description = property.PropertyType.Description;
|
||||
dest.Label = property.PropertyType.Name;
|
||||
dest.DataType = DataTypeService.GetDataType(property.PropertyType.DataTypeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,9 +383,12 @@ namespace Umbraco.Web.Models.Mapping
|
||||
target.AllowedAsRoot = source.AllowAsRoot;
|
||||
target.AllowedContentTypes = source.AllowedContentTypes.Select((t, i) => new ContentTypeSort(t, i));
|
||||
|
||||
target.Variations = ContentVariation.Nothing;
|
||||
if (!(target is IMemberType) && source.AllowCultureVariant)
|
||||
target.Variations |= ContentVariation.Culture;
|
||||
if (!(target is IMemberType))
|
||||
{
|
||||
target.Variations = ContentVariation.Nothing;
|
||||
if (source.AllowCultureVariant)
|
||||
target.Variations |= ContentVariation.Culture;
|
||||
}
|
||||
|
||||
// handle property groups and property types
|
||||
// note that ContentTypeSave has
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.ContentEditing;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.ContentApps;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Trees;
|
||||
using UserProfile = Umbraco.Web.Models.ContentEditing.UserProfile;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
@@ -42,10 +34,17 @@ namespace Umbraco.Web.Models.Mapping
|
||||
|
||||
public void SetMaps(Mapper mapper)
|
||||
{
|
||||
mapper.Define<IMedia, ContentPropertyCollectionDto>((source, context) => new ContentPropertyCollectionDto(), Map);
|
||||
mapper.Define<IMedia, MediaItemDisplay>((source, context) => new MediaItemDisplay(), Map);
|
||||
mapper.Define<IMedia, ContentItemBasic<ContentPropertyBasic>>((source, context) => new ContentItemBasic<ContentPropertyBasic>(), Map);
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(IMedia source, ContentPropertyCollectionDto target, MapperContext context)
|
||||
{
|
||||
target.Properties = source.Properties.Select(context.Mapper.Map<ContentPropertyDto>);
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll -Properties -Errors -Edited -Updater -Alias -IsContainer
|
||||
private void Map(IMedia source, MediaItemDisplay target, MapperContext context)
|
||||
{
|
||||
@@ -85,7 +84,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
target.Owner = _commonMapper.GetOwner(source, context.Mapper);
|
||||
target.ParentId = source.ParentId;
|
||||
target.Path = source.Path;
|
||||
target.Properties = context.Mapper.Map<IEnumerable<ContentPropertyBasic>>(source.Properties);
|
||||
target.Properties = source.Properties.Select(context.Mapper.Map<ContentPropertyBasic>);
|
||||
target.SortOrder = source.SortOrder;
|
||||
target.State = null;
|
||||
target.Trashed = source.Trashed;
|
||||
@@ -101,88 +100,4 @@ namespace Umbraco.Web.Models.Mapping
|
||||
return parent != null && (parent.ContentType.IsContainer || _mediaTypeService.HasContainerInPath(parent.Path));
|
||||
}
|
||||
}
|
||||
|
||||
// fixme temp + rename
|
||||
internal class CommonMapper
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider;
|
||||
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
|
||||
private readonly ContentAppFactoryCollection _contentAppDefinitions;
|
||||
private readonly ILocalizedTextService _localizedTextService;
|
||||
|
||||
public CommonMapper(IUserService userService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IUmbracoContextAccessor umbracoContextAccessor,
|
||||
ContentAppFactoryCollection contentAppDefinitions, ILocalizedTextService localizedTextService)
|
||||
{
|
||||
_userService = userService;
|
||||
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
_contentAppDefinitions = contentAppDefinitions;
|
||||
_localizedTextService = localizedTextService;
|
||||
}
|
||||
|
||||
public UserProfile GetOwner(IContentBase source, Mapper mapper)
|
||||
{
|
||||
var profile = source.GetCreatorProfile(_userService);
|
||||
return profile == null ? null : mapper.Map<IProfile, UserProfile>(profile);
|
||||
}
|
||||
|
||||
public UserProfile GetCreator(IContent source, Mapper mapper)
|
||||
{
|
||||
var profile = source.GetWriterProfile(_userService);
|
||||
return profile == null ? null : mapper.Map<IProfile, UserProfile>(profile);
|
||||
}
|
||||
|
||||
public ContentTypeBasic GetContentType(IContentBase source, Mapper mapper)
|
||||
{
|
||||
// TODO: We can resolve the UmbracoContext from the IValueResolver options!
|
||||
// OMG
|
||||
if (HttpContext.Current != null && Composing.Current.UmbracoContext != null && Composing.Current.UmbracoContext.Security.CurrentUser != null
|
||||
&& Composing.Current.UmbracoContext.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
|
||||
{
|
||||
var contentType = _contentTypeBaseServiceProvider.GetContentTypeOf(source);
|
||||
var contentTypeBasic = mapper.Map<IContentTypeComposition, ContentTypeBasic>(contentType);
|
||||
|
||||
return contentTypeBasic;
|
||||
}
|
||||
//no access
|
||||
return null;
|
||||
}
|
||||
|
||||
public string GetTreeNodeUrl<TController>(IContentBase source)
|
||||
where TController : ContentTreeControllerBase
|
||||
{
|
||||
var umbracoContext = _umbracoContextAccessor.UmbracoContext;
|
||||
if (umbracoContext == null) return null;
|
||||
|
||||
var urlHelper = new UrlHelper(umbracoContext.HttpContext.Request.RequestContext);
|
||||
return urlHelper.GetUmbracoApiService<TController>(controller => controller.GetTreeNode(source.Key.ToString("N"), null));
|
||||
}
|
||||
|
||||
public string GetMemberTreeNodeUrl(IContentBase source)
|
||||
{
|
||||
var umbracoContext = _umbracoContextAccessor.UmbracoContext;
|
||||
if (umbracoContext == null) return null;
|
||||
|
||||
var urlHelper = new UrlHelper(umbracoContext.HttpContext.Request.RequestContext);
|
||||
return urlHelper.GetUmbracoApiService<MemberTreeController>(controller => controller.GetTreeNode(source.Key.ToString("N"), null));
|
||||
}
|
||||
|
||||
public IEnumerable<ContentApp> GetContentApps(IContentBase source)
|
||||
{
|
||||
var apps = _contentAppDefinitions.GetContentAppsFor(source).ToArray();
|
||||
|
||||
// localize content app names
|
||||
foreach (var app in apps)
|
||||
{
|
||||
var localizedAppName = _localizedTextService.Localize($"apps/{app.Alias}");
|
||||
if (localizedAppName.Equals($"[{app.Alias}]", StringComparison.OrdinalIgnoreCase) == false)
|
||||
{
|
||||
app.Name = localizedAppName;
|
||||
}
|
||||
}
|
||||
|
||||
return apps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,14 +105,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
/// <returns></returns>
|
||||
protected virtual List<ContentPropertyDisplay> MapProperties(IContentBase content, List<Property> properties, MapperContext context)
|
||||
{
|
||||
//we need to map this way to pass the context through, I don't like it but we'll see what AutoMapper says: https://github.com/AutoMapper/AutoMapper/issues/2588
|
||||
var result = context.Mapper.Map<IEnumerable<Property>, IEnumerable<ContentPropertyDisplay>>(
|
||||
properties.OrderBy(prop => prop.PropertyType.SortOrder),
|
||||
null,
|
||||
context)
|
||||
.ToList();
|
||||
|
||||
return result;
|
||||
// must pass the context through
|
||||
return properties.OrderBy(x => x.PropertyType.SortOrder).Select(x => context.Mapper.Map<ContentPropertyDisplay>(x, context)).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
mapper.Define<UserGroupSave, IUserGroup>((source, context) => new UserGroup { CreateDate = DateTime.UtcNow }, Map);
|
||||
mapper.Define<UserInvite, IUser>(Map);
|
||||
mapper.Define<IProfile, ContentEditing.UserProfile>(Map);
|
||||
mapper.Define<IProfile, ContentEditing.UserProfile>((source, context) => new ContentEditing.UserProfile(), Map);
|
||||
mapper.Define<IReadOnlyUserGroup, UserGroupBasic>((source, context) => new UserGroupBasic(), Map);
|
||||
mapper.Define<IUserGroup, UserGroupBasic>((source, context) => new UserGroupBasic(), Map);
|
||||
mapper.Define<IUserGroup, AssignedUserGroupPermissions>((source, context) => new AssignedUserGroupPermissions(), Map);
|
||||
@@ -115,8 +115,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
private void Map(UserSave source, IUser target, MapperContext context)
|
||||
{
|
||||
target.Name = source.Name;
|
||||
target.StartContentIds = source.StartContentIds;
|
||||
target.StartMediaIds = source.StartMediaIds;
|
||||
target.StartContentIds = source.StartContentIds ?? Array.Empty<int>();
|
||||
target.StartMediaIds = source.StartMediaIds ?? Array.Empty<int>();
|
||||
target.Language = source.Culture;
|
||||
target.Email = source.Email;
|
||||
target.Key = source.Key;
|
||||
|
||||
@@ -204,6 +204,7 @@
|
||||
<Compile Include="Models\ContentEditing\LinkDisplay.cs" />
|
||||
<Compile Include="Models\ContentEditing\MacroDisplay.cs" />
|
||||
<Compile Include="Models\ContentEditing\MacroParameterDisplay.cs" />
|
||||
<Compile Include="Models\Mapping\CommonMapper.cs" />
|
||||
<Compile Include="Models\Mapping\MapperContextExtensions.cs" />
|
||||
<Compile Include="Models\PublishedContent\HybridVariationContextAccessor.cs" />
|
||||
<Compile Include="Models\TemplateQuery\QueryConditionExtensions.cs" />
|
||||
|
||||
Reference in New Issue
Block a user