Experiment with mapping (perfs)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using AutoMapper;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
|
||||
namespace Umbraco.Core.Composing.CompositionExtensions
|
||||
@@ -8,7 +8,9 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
||||
{
|
||||
public static Composition ComposeCoreMappingProfiles(this Composition composition)
|
||||
{
|
||||
composition.Register<Profile, IdentityMapperProfile>();
|
||||
composition.RegisterUnique<Mapper>();
|
||||
composition.WithCollectionBuilder<MapperProfileCollectionBuilder>()
|
||||
.Append<IdentityMapper>();
|
||||
return composition;
|
||||
}
|
||||
}
|
||||
|
||||
7
src/Umbraco.Core/Mapping/IMapperProfile.cs
Normal file
7
src/Umbraco.Core/Mapping/IMapperProfile.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Umbraco.Core.Mapping
|
||||
{
|
||||
public interface IMapperProfile
|
||||
{
|
||||
void SetMaps(Mapper mapper);
|
||||
}
|
||||
}
|
||||
50
src/Umbraco.Core/Mapping/Mapper.cs
Normal file
50
src/Umbraco.Core/Mapping/Mapper.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Mapping
|
||||
{
|
||||
public class Mapper
|
||||
{
|
||||
private readonly Dictionary<Type, Dictionary<Type, Func<object, object>>> _maps = new Dictionary<Type, Dictionary<Type, Func<object, object>>>();
|
||||
|
||||
public Mapper(MapperProfileCollection profiles)
|
||||
{
|
||||
foreach (var profile in profiles)
|
||||
profile.SetMaps(this);
|
||||
}
|
||||
|
||||
public void SetMap<TSource, TTarget>(Func<TSource, TTarget> map)
|
||||
{
|
||||
var sourceType = typeof(TSource);
|
||||
var targetType = typeof(TTarget);
|
||||
|
||||
if (!_maps.TryGetValue(sourceType, out var sourceMap))
|
||||
sourceMap = _maps[sourceType] = new Dictionary<Type, Func<object, object>>();
|
||||
|
||||
sourceMap[targetType] = o => map((TSource)o);
|
||||
}
|
||||
|
||||
public TTarget Map<TTarget>(object source)
|
||||
{
|
||||
if (source == null)
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
|
||||
var sourceType = source.GetType();
|
||||
var targetType = typeof(TTarget);
|
||||
|
||||
if (!_maps.TryGetValue(sourceType, out var sourceMap))
|
||||
{
|
||||
var type = _maps.Keys.FirstOrDefault(x => x.IsAssignableFrom(sourceType));
|
||||
if (type == null)
|
||||
throw new InvalidOperationException($"Don't know how to map {sourceType.FullName} to {targetType.FullName}.");
|
||||
sourceMap = _maps[sourceType] = _maps[type];
|
||||
}
|
||||
|
||||
if (!sourceMap.TryGetValue(targetType, out var map))
|
||||
throw new InvalidOperationException($"Don't know how to map {sourceType.FullName} to {targetType.FullName}.");
|
||||
|
||||
return (TTarget) map(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/Umbraco.Core/Mapping/MapperProfileCollection.cs
Normal file
12
src/Umbraco.Core/Mapping/MapperProfileCollection.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Core.Mapping
|
||||
{
|
||||
public class MapperProfileCollection : BuilderCollectionBase<IMapperProfile>
|
||||
{
|
||||
public MapperProfileCollection(IEnumerable<IMapperProfile> items)
|
||||
: base(items)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
11
src/Umbraco.Core/Mapping/MapperProfileCollectionBuilder.cs
Normal file
11
src/Umbraco.Core/Mapping/MapperProfileCollectionBuilder.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Core.Mapping
|
||||
{
|
||||
public class MapperProfileCollectionBuilder : OrderedCollectionBuilderBase<MapperProfileCollectionBuilder, MapperProfileCollection, IMapperProfile>
|
||||
{
|
||||
protected override MapperProfileCollectionBuilder This => this;
|
||||
|
||||
protected override Lifetime CollectionLifetime => Lifetime.Transient;
|
||||
}
|
||||
}
|
||||
@@ -1,53 +1,72 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
public class IdentityMapperProfile : Profile
|
||||
public class IdentityMapper : IMapperProfile
|
||||
{
|
||||
public IdentityMapperProfile(ILocalizedTextService textService, IEntityService entityService, IGlobalSettings globalSettings)
|
||||
private readonly ILocalizedTextService _textService;
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
|
||||
public IdentityMapper(ILocalizedTextService textService, IEntityService entityService, IGlobalSettings globalSettings)
|
||||
{
|
||||
CreateMap<IUser, BackOfficeIdentityUser>()
|
||||
.BeforeMap((src, dest) =>
|
||||
{
|
||||
dest.DisableChangeTracking();
|
||||
})
|
||||
.ConstructUsing(src => new BackOfficeIdentityUser(src.Id, src.Groups))
|
||||
.ForMember(dest => dest.LastLoginDateUtc, opt => opt.MapFrom(src => src.LastLoginDate.ToUniversalTime()))
|
||||
.ForMember(user => user.LastPasswordChangeDateUtc, expression => expression.MapFrom(user => user.LastPasswordChangeDate.ToUniversalTime()))
|
||||
.ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.Email))
|
||||
.ForMember(dest => dest.EmailConfirmed, opt => opt.MapFrom(src => src.EmailConfirmedDate.HasValue))
|
||||
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(dest => dest.LockoutEndDateUtc, opt => opt.MapFrom(src => src.IsLockedOut ? DateTime.MaxValue.ToUniversalTime() : (DateTime?) null))
|
||||
.ForMember(dest => dest.IsApproved, opt => opt.MapFrom(src => src.IsApproved))
|
||||
.ForMember(dest => dest.UserName, opt => opt.MapFrom(src => src.Username))
|
||||
.ForMember(dest => dest.PasswordHash, opt => opt.MapFrom(user => GetPasswordHash(user.RawPasswordValue)))
|
||||
.ForMember(dest => dest.Culture, opt => opt.MapFrom(src => src.GetUserCulture(textService, globalSettings)))
|
||||
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name))
|
||||
.ForMember(dest => dest.StartMediaIds, opt => opt.MapFrom(src => src.StartMediaIds))
|
||||
.ForMember(dest => dest.StartContentIds, opt => opt.MapFrom(src => src.StartContentIds))
|
||||
.ForMember(dest => dest.AccessFailedCount, opt => opt.MapFrom(src => src.FailedPasswordAttempts))
|
||||
.ForMember(dest => dest.CalculatedContentStartNodeIds, opt => opt.MapFrom(src => src.CalculateContentStartNodeIds(entityService)))
|
||||
.ForMember(dest => dest.CalculatedMediaStartNodeIds, opt => opt.MapFrom(src => src.CalculateMediaStartNodeIds(entityService)))
|
||||
.ForMember(dest => dest.AllowedSections, opt => opt.MapFrom(src => src.AllowedSections.ToArray()))
|
||||
.ForMember(dest => dest.LockoutEnabled, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Logins, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.EmailConfirmed, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.PhoneNumber, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.PhoneNumberConfirmed, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.TwoFactorEnabled, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Roles, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Claims, opt => opt.Ignore())
|
||||
.AfterMap((src, dest) =>
|
||||
{
|
||||
dest.ResetDirtyProperties(true);
|
||||
dest.EnableChangeTracking();
|
||||
});
|
||||
_textService = textService;
|
||||
_entityService = entityService;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
public void SetMaps(Mapper mapper)
|
||||
{
|
||||
mapper.SetMap<IUser, BackOfficeIdentityUser>(Map);
|
||||
}
|
||||
|
||||
public BackOfficeIdentityUser Map(IUser source)
|
||||
{
|
||||
// AssignAll enable
|
||||
var target = new BackOfficeIdentityUser(source.Id, source.Groups)
|
||||
{
|
||||
// ignored
|
||||
//Groups = ,
|
||||
//LockoutEnabled = ,
|
||||
//PhoneNumber = ,
|
||||
//PhoneNumberConfirmed = ,
|
||||
//TwoFactorEnabled = ,
|
||||
|
||||
Id = source.Id, // also in ctor but required, BackOfficeIdentityUser is weird
|
||||
CalculatedMediaStartNodeIds = source.CalculateMediaStartNodeIds(_entityService),
|
||||
CalculatedContentStartNodeIds = source.CalculateContentStartNodeIds(_entityService),
|
||||
Email = source.Email,
|
||||
UserName = source.Username,
|
||||
LastPasswordChangeDateUtc = source.LastPasswordChangeDate.ToUniversalTime(),
|
||||
LastLoginDateUtc = source.LastLoginDate.ToUniversalTime(),
|
||||
EmailConfirmed = source.EmailConfirmedDate.HasValue,
|
||||
Name = source.Name,
|
||||
AccessFailedCount = source.FailedPasswordAttempts,
|
||||
PasswordHash = GetPasswordHash(source.RawPasswordValue),
|
||||
StartContentIds = source.StartContentIds,
|
||||
StartMediaIds = source.StartMediaIds,
|
||||
Culture = source.GetUserCulture(_textService, _globalSettings).ToString(), // project CultureInfo to string
|
||||
IsApproved = source.IsApproved,
|
||||
SecurityStamp = source.SecurityStamp,
|
||||
LockoutEndDateUtc = source.IsLockedOut ? DateTime.MaxValue.ToUniversalTime() : (DateTime?)null,
|
||||
|
||||
// this was in AutoMapper but does not have a setter anyways
|
||||
//AllowedSections = source.AllowedSections.ToArray(),
|
||||
|
||||
// these were marked as ignored for AutoMapper but don't have a setter anyways
|
||||
//Logins =,
|
||||
//Claims =,
|
||||
//Roles =,
|
||||
};
|
||||
|
||||
target.ResetDirtyProperties(true);
|
||||
target.EnableChangeTracking(); // fixme but how can we disable it?
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
private static string GetPasswordHash(string storedPass)
|
||||
|
||||
@@ -10,11 +10,13 @@ using Microsoft.AspNet.Identity;
|
||||
using Microsoft.Owin;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
using IUser = Umbraco.Core.Models.Membership.IUser;
|
||||
using Mapper = Umbraco.Core.Mapping.Mapper;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
@@ -185,7 +187,10 @@ namespace Umbraco.Core.Security
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return await Task.FromResult(AssignLoginsCallback(Mapper.Map<BackOfficeIdentityUser>(user)));
|
||||
|
||||
var m = Composing.Current.Factory.GetInstance<Mapper>();
|
||||
//return await Task.FromResult(AssignLoginsCallback(Mapper.Map<BackOfficeIdentityUser>(user)));
|
||||
return await Task.FromResult(AssignLoginsCallback(m.Map<BackOfficeIdentityUser>(user)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -202,7 +207,9 @@ namespace Umbraco.Core.Security
|
||||
return null;
|
||||
}
|
||||
|
||||
var result = AssignLoginsCallback(Mapper.Map<BackOfficeIdentityUser>(user));
|
||||
var m = Composing.Current.Factory.GetInstance<Mapper>();
|
||||
//var result = AssignLoginsCallback(Mapper.Map<BackOfficeIdentityUser>(user));
|
||||
var result = AssignLoginsCallback(m.Map<BackOfficeIdentityUser>(user));
|
||||
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
@@ -311,10 +318,12 @@ namespace Umbraco.Core.Security
|
||||
public Task<BackOfficeIdentityUser> FindByEmailAsync(string email)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
var m = Composing.Current.Factory.GetInstance<Mapper>();
|
||||
var user = _userService.GetByEmail(email);
|
||||
var result = user == null
|
||||
? null
|
||||
: Mapper.Map<BackOfficeIdentityUser>(user);
|
||||
//: Mapper.Map<BackOfficeIdentityUser>(user);
|
||||
: m.Map<BackOfficeIdentityUser>(user);
|
||||
|
||||
return Task.FromResult(AssignLoginsCallback(result));
|
||||
}
|
||||
@@ -391,7 +400,9 @@ namespace Umbraco.Core.Security
|
||||
var user = _userService.GetUserById(l.UserId);
|
||||
if (user != null)
|
||||
{
|
||||
output = Mapper.Map<BackOfficeIdentityUser>(user);
|
||||
var m = Composing.Current.Factory.GetInstance<Mapper>();
|
||||
//output = Mapper.Map<BackOfficeIdentityUser>(user);
|
||||
output = m.Map<BackOfficeIdentityUser>(user);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,11 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<!-- note: NuGet deals with transitive references now -->
|
||||
<PackageReference Include="AssignAll">
|
||||
<Version>1.0.7017.28472</Version>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="AutoMapper" Version="8.0.0" />
|
||||
<PackageReference Include="LightInject" Version="5.4.0" />
|
||||
<PackageReference Include="LightInject.Annotation" Version="1.1.0" />
|
||||
@@ -209,6 +214,10 @@
|
||||
<Compile Include="IO\MediaPathSchemes\UniqueMediaPathScheme.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\MergeDateAndDateTimePropertyEditor.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_1\ChangeNuCacheJsonFormat.cs" />
|
||||
<Compile Include="Mapping\MapperProfileCollection.cs" />
|
||||
<Compile Include="Mapping\MapperProfileCollectionBuilder.cs" />
|
||||
<Compile Include="Mapping\IMapperProfile.cs" />
|
||||
<Compile Include="Mapping\Mapper.cs" />
|
||||
<Compile Include="Models\PublishedContent\ILivePublishedModelFactory.cs" />
|
||||
<Compile Include="PropertyEditors\DateTimeConfiguration.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\RenameLabelAndRichTextPropertyEditorAliases.cs" />
|
||||
|
||||
@@ -8,10 +8,12 @@ using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Web.Security;
|
||||
using Mapper = Umbraco.Core.Mapping.Mapper;
|
||||
using UserExtensions = Umbraco.Core.Models.UserExtensions;
|
||||
|
||||
namespace Umbraco.Web.WebApi.Filters
|
||||
@@ -112,7 +114,9 @@ namespace Umbraco.Web.WebApi.Filters
|
||||
{
|
||||
var signInManager = owinCtx.Result.GetBackOfficeSignInManager();
|
||||
|
||||
var backOfficeIdentityUser = Mapper.Map<BackOfficeIdentityUser>(user);
|
||||
var m = Composing.Current.Factory.GetInstance<Mapper>();
|
||||
//var backOfficeIdentityUser = Mapper.Map<BackOfficeIdentityUser>(user);
|
||||
var backOfficeIdentityUser = m.Map<BackOfficeIdentityUser>(user);
|
||||
await signInManager.SignInAsync(backOfficeIdentityUser, isPersistent: true, rememberBrowser: false);
|
||||
|
||||
//ensure the remainder of the request has the correct principal set
|
||||
|
||||
Reference in New Issue
Block a user