Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit 7d41a68

Browse files
committed
Add RegisterPopulator AutoMapping API
1 parent 5dd7e0d commit 7d41a68

File tree

3 files changed

+103
-4
lines changed

3 files changed

+103
-4
lines changed

src/ServiceStack.Text/AutoMappingUtils.cs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,22 @@ public static void IgnoreMapping(Type fromType, Type toType)
4444
JsConfig.InitStatics();
4545
AutoMappingUtils.ignoreMappings[Tuple.Create(fromType, toType)] = true;
4646
}
47+
48+
public static void RegisterPopulator<Target, Source>(Action<Target, Source> populator)
49+
{
50+
JsConfig.InitStatics();
51+
AutoMappingUtils.populators[Tuple.Create(typeof(Target), typeof(Source))] = (a,b) => populator((Target)a,(Source)b);
52+
}
4753
}
4854

4955
public static class AutoMappingUtils
5056
{
5157
internal static readonly ConcurrentDictionary<Tuple<Type, Type>, GetMemberDelegate> converters
5258
= new ConcurrentDictionary<Tuple<Type, Type>, GetMemberDelegate>();
5359

60+
internal static readonly ConcurrentDictionary<Tuple<Type, Type>, PopulateMemberDelegate> populators
61+
= new ConcurrentDictionary<Tuple<Type, Type>, PopulateMemberDelegate>();
62+
5463
internal static readonly ConcurrentDictionary<Tuple<Type, Type>,bool> ignoreMappings
5564
= new ConcurrentDictionary<Tuple<Type, Type>,bool>();
5665

@@ -60,9 +69,6 @@ public static void Reset()
6069
ignoreMappings.Clear();
6170
AssignmentDefinitionCache.Clear();
6271
}
63-
64-
[Obsolete("Use AutoMapping.RegisterConverter")]
65-
public static void RegisterConverter<From, To>(Func<From, To> converter) => throw new NotSupportedException("Deprecated: Use AutoMapping.RegisterConverter");
6672

6773
public static bool ShouldIgnoreMapping(Type fromType, Type toType) =>
6874
ignoreMappings.ContainsKey(Tuple.Create(fromType, toType));
@@ -78,6 +84,17 @@ public static GetMemberDelegate GetConverter(Type fromType, Type toType)
7884
: null;
7985
}
8086

87+
public static PopulateMemberDelegate GetPopulator(Type targetType, Type sourceType)
88+
{
89+
if (populators.IsEmpty)
90+
return null;
91+
92+
var key = Tuple.Create(targetType, sourceType);
93+
return populators.TryGetValue(key, out var populator)
94+
? populator
95+
: null;
96+
}
97+
8198
public static T ConvertTo<T>(this object from, T defaultValue) =>
8299
from == null || (from is string s && s == string.Empty)
83100
? defaultValue
@@ -1175,12 +1192,17 @@ public void Populate(object to, object from,
11751192
ToType.FullName, toType.Name, ex);
11761193
}
11771194
}
1195+
1196+
var populator = AutoMappingUtils.GetPopulator(to.GetType(), from.GetType());
1197+
populator?.Invoke(to, from);
11781198
}
11791199
}
11801200

11811201
public delegate object GetMemberDelegate(object instance);
11821202
public delegate object GetMemberDelegate<T>(T instance);
11831203

1204+
public delegate void PopulateMemberDelegate(object target, object source);
1205+
11841206
public delegate void SetMemberDelegate(object instance, object value);
11851207
public delegate void SetMemberDelegate<T>(T instance, object value);
11861208
public delegate void SetMemberRefDelegate(ref object instance, object propertyValue);

src/ServiceStack.Text/Common/JsWriter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ static JsWriter()
4242
{
4343
EscapeCharFlags[escapeChar] = true;
4444
}
45-
var loadConfig = JsConfig.EmitCamelCaseNames; //force load
45+
var loadConfig = JsConfig.TextCase; //force load
4646
}
4747

4848
public static void WriteDynamic(Action callback)
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using NUnit.Framework;
2+
3+
namespace ServiceStack.Text.Tests
4+
{
5+
public class AutoMappingPopulatorTests
6+
{
7+
private static User CreateUser() =>
8+
new User {
9+
FirstName = "John",
10+
LastName = "Doe",
11+
Car = new Car {Name = "BMW X6", Age = 3}
12+
};
13+
14+
private static UsersData CreateUserData()
15+
{
16+
var user = CreateUser();
17+
return new UsersData {
18+
Id = 1,
19+
User = user,
20+
UsersList = {user},
21+
UsersMap = {{1, user}}
22+
};
23+
}
24+
25+
[Test]
26+
public void Does_call_populator_for_PopulateWith()
27+
{
28+
AutoMapping.RegisterPopulator((UserDto target, User source) =>
29+
target.LastName += "?!");
30+
31+
var user = CreateUser();
32+
var dtoUser = new UserDto().PopulateWith(user);
33+
34+
Assert.That(dtoUser.FirstName, Is.EqualTo(user.FirstName));
35+
Assert.That(dtoUser.LastName, Is.EqualTo(user.LastName + "?!"));
36+
}
37+
38+
[Test]
39+
public void Does_call_populator_for_PopulateWithNonDefaultValues()
40+
{
41+
AutoMapping.RegisterPopulator((UserDto target, User source) =>
42+
target.LastName += "?!");
43+
44+
var user = CreateUser();
45+
var dtoUser = new UserDto().PopulateWithNonDefaultValues(user);
46+
47+
Assert.That(dtoUser.FirstName, Is.EqualTo(user.FirstName));
48+
Assert.That(dtoUser.LastName, Is.EqualTo(user.LastName + "?!"));
49+
}
50+
51+
[Test]
52+
public void Does_call_populator_for_PopulateFromPropertiesWithoutAttribute()
53+
{
54+
AutoMapping.RegisterPopulator((UserDto target, User source) =>
55+
target.LastName += "?!");
56+
57+
var user = CreateUser();
58+
var dtoUser = new UserDto().PopulateFromPropertiesWithoutAttribute(user, typeof(IgnoreAttribute));
59+
60+
Assert.That(dtoUser.FirstName, Is.EqualTo(user.FirstName));
61+
Assert.That(dtoUser.LastName, Is.EqualTo(user.LastName + "?!"));
62+
}
63+
64+
[Test]
65+
public void Does_call_populator_for_ConvertTo()
66+
{
67+
AutoMapping.RegisterPopulator((UserDto target, User source) =>
68+
target.LastName += "?!");
69+
70+
var user = CreateUser();
71+
var dtoUser = user.ConvertTo<UserDto>();
72+
73+
Assert.That(dtoUser.FirstName, Is.EqualTo(user.FirstName));
74+
Assert.That(dtoUser.LastName, Is.EqualTo(user.LastName + "?!"));
75+
}
76+
}
77+
}

0 commit comments

Comments
 (0)