Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create explicit scope for mappers in UmbracoMapper #9995

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 22 additions & 7 deletions src/Umbraco.Core/Mapping/UmbracoMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Scoping;

namespace Umbraco.Core.Mapping
{
Expand Down Expand Up @@ -42,12 +43,17 @@ private readonly ConcurrentDictionary<Type, Dictionary<Type, Func<object, Mapper
private readonly ConcurrentDictionary<Type, Dictionary<Type, Action<object, object, MapperContext>>> _maps
= new ConcurrentDictionary<Type, Dictionary<Type, Action<object, object, MapperContext>>>();

private readonly IScopeProvider _scopeProvider;

/// <summary>
/// Initializes a new instance of the <see cref="UmbracoMapper"/> class.
/// </summary>
/// <param name="profiles"></param>
public UmbracoMapper(MapDefinitionCollection profiles)
/// <param name="scopeProvider"></param>
public UmbracoMapper(MapDefinitionCollection profiles, IScopeProvider scopeProvider)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should make this ctor non-breaking by obsoleting the old one and adding a new one and calling: this(profiles, Current.ScopeProvider)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah very good point, didn't think of that, I've re-added the old constructor using Current.ScopeProvider and marked it as obsolete 👍

{
_scopeProvider = scopeProvider;

foreach (var profile in profiles)
profile.DefineMaps(this);
}
Expand Down Expand Up @@ -203,7 +209,10 @@ private TTarget Map<TTarget>(object source, Type sourceType, MapperContext conte
if (ctor != null && map != null)
{
var target = ctor(source, context);
map(source, target, context);
using (var scope = _scopeProvider.CreateScope(autoComplete: true))
{
map(source, target, context);
}
return (TTarget)target;
}

Expand Down Expand Up @@ -248,11 +257,14 @@ private TTarget MapEnumerableInternal<TTarget>(IEnumerable source, Type targetGe
{
var targetList = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(targetGenericArg));

foreach (var sourceItem in source)
using (var scope = _scopeProvider.CreateScope(autoComplete: true))
{
var targetItem = ctor(sourceItem, context);
map(sourceItem, targetItem, context);
targetList.Add(targetItem);
foreach (var sourceItem in source)
{
var targetItem = ctor(sourceItem, context);
map(sourceItem, targetItem, context);
targetList.Add(targetItem);
}
}

object target = targetList;
Expand Down Expand Up @@ -315,7 +327,10 @@ public TTarget Map<TSource, TTarget>(TSource source, TTarget target, MapperConte
// if there is a direct map, map
if (map != null)
{
map(source, target, context);
using (var scope = _scopeProvider.CreateScope(autoComplete: true))
{
map(source, target, context);
}
return target;
}

Expand Down
37 changes: 30 additions & 7 deletions src/Umbraco.Tests/Mapping/MappingTests.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,48 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading;
using Moq;
using NUnit.Framework;
using Umbraco.Core.Events;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models;
using Umbraco.Core.Scoping;
using Umbraco.Web.Models.ContentEditing;
using PropertyCollection = Umbraco.Core.Models.PropertyCollection;

namespace Umbraco.Tests.Mapping
{
[TestFixture]
public class MappingTests
{
private IScopeProvider _scopeProvider;

[SetUp]
public void MockScopeProvider()
{
var scopeMock = new Mock<IScopeProvider>();
scopeMock.Setup(x => x.CreateScope(
It.IsAny<IsolationLevel>(),
It.IsAny<RepositoryCacheMode>(),
It.IsAny<IEventDispatcher>(),
It.IsAny<bool?>(),
It.IsAny<bool>(),
It.IsAny<bool>()))
.Returns(Mock.Of<IScope>);

_scopeProvider = scopeMock.Object;
}

[Test]
public void SimpleMap()
{
var definitions = new MapDefinitionCollection(new IMapDefinition[]
{
new MapperDefinition1(),
});
var mapper = new UmbracoMapper(definitions);
var mapper = new UmbracoMapper(definitions, _scopeProvider);

var thing1 = new Thing1 { Value = "value" };
var thing2 = mapper.Map<Thing1, Thing2>(thing1);
Expand All @@ -44,7 +67,7 @@ public void EnumerableMap()
{
new MapperDefinition1(),
});
var mapper = new UmbracoMapper(definitions);
var mapper = new UmbracoMapper(definitions, _scopeProvider);

var thing1A = new Thing1 { Value = "valueA" };
var thing1B = new Thing1 { Value = "valueB" };
Expand Down Expand Up @@ -78,7 +101,7 @@ public void InheritedMap()
{
new MapperDefinition1(),
});
var mapper = new UmbracoMapper(definitions);
var mapper = new UmbracoMapper(definitions, _scopeProvider);

var thing3 = new Thing3 { Value = "value" };
var thing2 = mapper.Map<Thing3, Thing2>(thing3);
Expand All @@ -103,7 +126,7 @@ public void CollectionsMap()
{
new MapperDefinition2(),
});
var mapper = new UmbracoMapper(definitions);
var mapper = new UmbracoMapper(definitions, _scopeProvider);

// can map a PropertyCollection
var source = new PropertyCollection();
Expand All @@ -119,7 +142,7 @@ public void ConcurrentMap()
new MapperDefinition1(),
new MapperDefinition3(),
});
var mapper = new UmbracoMapper(definitions);
var mapper = new UmbracoMapper(definitions, _scopeProvider);

// the mapper currently has a map from Thing1 to Thing2
// because Thing3 inherits from Thing1, it will map a Thing3 instance,
Expand Down Expand Up @@ -179,7 +202,7 @@ public void EnumMap()
{
new MapperDefinition4(),
});
var mapper = new UmbracoMapper(definitions);
var mapper = new UmbracoMapper(definitions, _scopeProvider);

var thing5 = new Thing5()
{
Expand All @@ -203,7 +226,7 @@ public void NullPropertyMap()
{
new MapperDefinition5(),
});
var mapper = new UmbracoMapper(definitions);
var mapper = new UmbracoMapper(definitions, _scopeProvider);

var thing7 = new Thing7();

Expand Down
18 changes: 16 additions & 2 deletions src/Umbraco.Tests/Testing/TestingTests/MockTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Web.Security;
Expand All @@ -9,11 +10,13 @@
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Dictionary;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Persistence;
using Umbraco.Core.Scoping;
using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Stubs;
Expand Down Expand Up @@ -98,10 +101,21 @@ public void Can_Mock_UmbracoApiController_Dependencies_With_Injected_UmbracoMapp
{
var umbracoContext = TestObjects.GetUmbracoContextMock();

var scopeProvider = new Mock<IScopeProvider>();
scopeProvider
.Setup(x => x.CreateScope(
It.IsAny<IsolationLevel>(),
It.IsAny<RepositoryCacheMode>(),
It.IsAny<IEventDispatcher>(),
It.IsAny<bool?>(),
It.IsAny<bool>(),
It.IsAny<bool>()))
.Returns(Mock.Of<IScope>);

var membershipHelper = new MembershipHelper(umbracoContext.HttpContext, Mock.Of<IPublishedMemberCache>(), Mock.Of<MembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), Mock.Of<AppCaches>(), Mock.Of<ILogger>());
var umbracoHelper = new UmbracoHelper(Mock.Of<IPublishedContent>(), Mock.Of<ITagQuery>(), Mock.Of<ICultureDictionaryFactory>(), Mock.Of<IUmbracoComponentRenderer>(), Mock.Of<IPublishedContentQuery>(), membershipHelper);
var umbracoMapper = new UmbracoMapper(new MapDefinitionCollection(new[] { Mock.Of<IMapDefinition>() }));
var umbracoMapper = new UmbracoMapper(new MapDefinitionCollection(new[] { Mock.Of<IMapDefinition>() }), scopeProvider.Object);

// ReSharper disable once UnusedVariable
var umbracoApiController = new FakeUmbracoApiController(Mock.Of<IGlobalSettings>(), Mock.Of<IUmbracoContextAccessor>(), Mock.Of<ISqlContext>(), ServiceContext.CreatePartial(), AppCaches.NoCache, Mock.Of<IProfilingLogger>(), Mock.Of<IRuntimeState>(), umbracoHelper, umbracoMapper);

Expand Down