Applying DRY to Autofixture "Build" statements - c#

Assume I have this concrete class:
public partial class User
{
public int ID { get; set; }
public string Email { get; set; }
public string FullName { get; set; }
}
And I want to create an anonymous instance that has a valid email address, and the fullname field is no more than 20 characters. I can do this:
var fixture = new Fixture();
var anonUser = fixture.Build<User>()
.With(x => x.Email, string.Format("{0}#fobar.com", fixture.Create<string>()))
.With(x => x.FullName, fixture.Create<string>()Substring(0,20))
.Create();
Is there a way that I can define this in one place, so that AF knows that I can get my customized anon class by using:
var newAnon = fixture.Build<User>();

You have various options. In my opinion, the best option is to apply the GOOS principle of listening to your tests. When the test becomes difficult to write, it's time to reconsider the design of the System Under Test (SUT). AutoFixture tends to amplify this effect.
Refactor to Value Objects
If you have a requirement that the Email and FullName properties should have particularly constrained values, it might indicate that instead of Primitive Obsession, the target API would benefit from defining explicit Email and FullName Value Objects. The canonical AutoFixture example is about phone numbers.
Use data annotations
You can also use data annotations to give AutoFixture hints about the constraints of the values. Not all data annotation attributes are supported, but you can use both MaxLength and RegularExpression.
It might look something like this:
public partial class User
{
public int ID { get; set; }
[RegularExpression("regex for emails is much harder than you think")]
public string Email { get; set; }
[MaxLenght(20)]
public string FullName { get; set; }
}
Personally, I don't like this approach, because I prefer proper encapsulation instead.
Use Customize
Instead of using the Build<T> method, use the Customize<T> method:
var fixture = new Fixture();
fixture.Customize<User>(c => c
.With(x => x.Email, string.Format("{0}#fobar.com", fixture.Create<string>())
.With(x => x.FullName, fixture.Create<string>().Substring(0,20)));
var newAnon = fixture.Create<User>();
Write a convention-driven Specimen Builder
Finally, you can write a convention-driven customization:
public class EmailSpecimenBuilder : ISpecimenBuilder
{
public object Create(object request,
ISpecimenContext context)
{
var pi = request as PropertyInfo;
if (pi == null)
{
return new NoSpecimen(request);
}
if (pi.PropertyType != typeof(string)
|| pi.Name != "Email")
{
return new NoSpecimen(request);
}
return string.Format("{0}#fobar.com", context.Resolve(typeof(string)));
}
}
This approach I really like, because I can put arbitrarily complex logic here, so instead of having to create a lot of one-off customizations, I can have a small set of conventions driving an entire test suite. This also tends to make the target code more consistent.

Related

How to return a specific property in the message of a RuleForEach validation, using Fluent Validator?

Let's say I have a test class like this:
public class TestClass
{
public Properties[] TestProperties { get; set; }
public Guid Id { get; set; }
public TestClass(Properties[] testProperties)
{
Id = Guid.NewGuid();
TestProperties = testProperties;
}
}
And a Properties class as follows:
public class Properties
{
public Guid Id { get; set; }
public string Name { get; set; }
public Properties(string name)
{
Name = name;
Id = Guid.NewGuid();
}
}
I need to validate that none of my properties Name at the TestProperties array is null, like this:
public class TestValidator : AbstractValidator<TestClass>
{
public TestValidator()
{
RuleForEach(x => x.TestProperties)
.Must(y => y.Name != string.Empty && y.Name != null)
.WithMessage("TestPropertie at {CollectionIndex}, can't be null or empty");
}
}
But instead of returning the position of the failing property, at the validation message, I would like to return it's Id, how can I do so?
Yes, using the default validators it's possible to inject other property values from the objects into the message.
This can be done by using the overload of WithMessage that takes a
lambda expression, and then passing the values to string.Format or by
using string interpolation.
Source
There are a couple of ways you can do it. Firstly, as per your current implementation using Must:
public class TestClassValidator : AbstractValidator<TestClass>
{
public TestClassValidator()
{
RuleForEach(x => x.TestProperties)
.Must(y => !string.IsNullOrEmpty(y.Name))
.WithMessage((testClass, testProperty) => $"TestProperty {testProperty.Id} name can't be null or empty");
}
}
I try to avoid using Must when possible, if you stick to using the built-in validators you stand a better chance of client-side validation working out of the box (if you're using it in a web app). Using ChildRules allows you to use the built-in validators and also get the benefit of using the fluent interface:
public class TestClassValidator : AbstractValidator<TestClass>
{
public TestClassValidator()
{
RuleForEach(x => x.TestProperties)
.ChildRules(testProperties =>
{
testProperties.RuleFor(testProperty => testProperty.Name)
.NotNull()
.NotEmpty()
.WithMessage(testProperty => $"TestProperty {testProperty.Id} name can't be null or empty");
});
}
}
ChildRules doco
I've included the NotNull() validator for verbosity/alignment with the custom error message, however it's not needed as NotEmpty() will cover the null or empty case.
Finally if it was me I'd probably create a separate validator for the Properties type (should this be Property?) and use SetValidator to include it. Splits up the validation concerns, defines the validation for a type once and makes the rules reusable, and makes the validators easier to test. I'm not going to cover that here as that feels beyond the scope of this question but the links below give examples on how to do it.
Child validator doco (SetValidator usage) here and here
Working samples of the above including tests can be found here.
I approached this a little differently, because I wanted a more reusable solution. (I'm validating many different classes in similar ways). Putting the message identification inside the extension with Must<> ties you to the type and could lead to copy&paste. Instead, I pass as an argument to the validation, a Func that returns an identifying string and lets the caller decide how to identify the object being validated.
public static IRuleBuilderOptions<T, string> IsValidStringEnumAllowNullable<T>(this IRuleBuilder<T, string> ruleBuilder, IList<string> validValues, Func<T,string> identifierLookup)
{
return ruleBuilder.Must((rootObject, testValue, context) =>
{
context.MessageFormatter.AppendArgument("AllowableValues", string.Join(", ", validValues));
context.MessageFormatter.AppendArgument("Identifier", identifierLookup(rootObject));
return string.IsNullOrEmpty(testValue) || validValues.Contains(testValue, StringComparer.Ordinal);
}).WithMessage("{Identifier}{PropertyName} with value {PropertyValue} must be one of the allowable values: {AllowableValues}, or null or empty string");
}
And then the calling code where I tell the specific validation message 'how' to identify the object for messaging:
base.RuleForEach(rq => rq.Thingies).ChildRules(x =>
{
x.RuleFor(f => f.MyProperty).IsValidStringEnumAllowNullable(ValidationStrings.AnArrayOfAllowedValues, f => $"Thing[{f.Id}] ");
});
The result of this code is
Thing[1234] My Property with value asdf must be one of the allowable values: Value1, ValidValue2, Somethingelse, or null or empty string

How to ignore a property based on a runtime condition?

I have a simple pair of classes which for I've set up a mapping at initialization time.
public class Order {
public int ID { get; set; }
public string Foo { get; set; }
}
public class OrderDTO {
public int ID { get; set; }
public string Foo { get; set; }
}
...
Mapper.CreateMap<Order, OrderDTO>();
Now at a certain point I need to map an Order to an OrderDTO. BUT depending on some circumstances, I might need to ignore Foo during mapping. Let's also assume that I cannot "store" the condition in the source or destination object.
I know how I can configure the ignored properties at initialization time, but I have no idea how I could achieve such a dynamic runtime behavior.
Any help would be appreciated.
UPDATE
My use case for this behaviour is something like this. I have an ASP.NET MVC web grid view which displays a list of OrderDTOs. The users can edit the cell values individually. The grid view sends the edited data back to the server like a collection of OrderDTOs, BUT only the edited field values are set, the others are left as default. It also sends data about which fields are edited for each primary key. Now from this special scenario I need to map these "half-empty" objects to Orders, but of course, skip those properties which were not edited for each object.
The other way would be to do the manual mapping, or use Reflection somehow, but I was just thinking about if I could use AutoMapper in some way.
I've digged into the AutoMapper source code and samples, and found that there is a way to pass runtime parameters at mapping time.
A quick example setup and usage looks like this.
public class Order {
public int ID { get; set; }
public string Foo { get; set; }
}
public class OrderDTO {
public int ID { get; set; }
public string Foo { get; set; }
}
...
Mapper.CreateMap<Order, OrderDTO>()
.ForMember(e => e.Foo, o => o.Condition((ResolutionContext c) => !c.Options.Items.ContainsKey("IWantToSkipFoo")));
...
var target = new Order();
target.ID = 2;
target.Foo = "This should not change";
var source = new OrderDTO();
source.ID = 10;
source.Foo = "This won't be mapped";
Mapper.Map(source, target, opts => { opts.Items["IWantToSkipFoo"] = true; });
Assert.AreEqual(target.ID, 10);
Assert.AreEqual(target.Foo, "This should not change");
In fact this looks quite "technical", but I still think there are quite many use cases when this is really helpful. If this logic is generalized according to application needs, and wrapped into some extension methods for example, then it could be much cleaner.
Expanding on BlackjacketMack's comment for others:
In your MappingProfile, add a ForAllMaps(...) call to your constructor.
using AutoMapper;
using System.Collections.Generic;
using System.Linq;
public class MappingProfile : Profile
{
public MappingProfile()
{
ForAllMaps((typeMap, mappingExpression) =>
{
mappingExpression.ForAllMembers(memberOptions =>
{
memberOptions.Condition((o1, o2, o3, o4, resolutionContext) =>
{
var name = memberOptions.DestinationMember.Name;
if (resolutionContext.Items.TryGetValue(MemberExclusionKey, out object exclusions))
{
if (((IEnumerable<string>)exclusions).Contains(name))
{
return false;
}
}
return true;
});
});
});
}
public static string MemberExclusionKey { get; } = "exclude";
}
Then, for ease of use, add the following class to create an extension method for yourself.
public static class IMappingOperationOptionsExtensions
{
public static void ExcludeMembers(this AutoMapper.IMappingOperationOptions options, params string[] members)
{
options.Items[MappingProfile.MemberExclusionKey] = members;
}
}
Finally, tie it all together: var target = mapper.Map<Order>(source, opts => opts.ExcludeMembers("Foo"));

ServiceStack support for conditionally omitting fields from a REST response on a per-call basis

<TL;DR>
At a minimum, I'm looking for a way to conditionally exclude certain properties on the resource from being included in the response on a per-call basis (See fields below).
Ideally, I'd like to implement a REST service with ServiceStack that supports all the major points below.
UPDATE
While I really like ServiceStack's approach in general and would prefer to use it if possible, if it isn't particularly well suited towards these ideas I'd rather not bend over backwards bastardizing it to make it work. If that's the case, can anyone point to another c# framework that might be more appropriate? I'm actively exploring other options myself, of course.
</TD;DR>
In this talk entitled Designing REST + JSON APIs, the presenter describes his strategy for Resource References (via href property on resources) in JSON. In addition to this, he describes two query parameters (fields and expand) for controlling what data is included the response of a call to a REST service. I've been trying without success to dig into the ServiceStack framework to achieve support for fields in particular but have thus far been unsuccessful. Is this currently possible in ServiceStack? Ideally the solution would be format agnostic and would therefore work across all of ServiceStack's supported output formats. I would imagine expand would follow the same strategy.
I'll describe these features here but I think the talk at the link does a better job of explaining them.
Lets say we have an Profiles resource with the following properties: givenName, surname, gender, and favColor. The Profiles resource also includes a list of social networks the user belongs to in the socialNetworks property.
href - (42:22 in video) Every resource includes a full link to it on the REST service. A call to GET /profiles/123 would return
{
"href":"https://host/profiles/123",
"givenName":"Bob",
"surname":"Smith",
"gender":"male",
"favColor":"red",
"socialNetworks": {
"href":"https://host/socialNetworkMemberships?profileId=123"
}
}
Notice that the socialNetworks property returns an object with just the href value populated. This keeps the response short and focused while also giving the end user enough information to make further requests if desired. The href property, used across the board in this manor, makes it easy (conceptually anyway) to reuse resource data structures as children of other resources.
fields - (55:44 in video) Query string parameter that instructs the server to only include the specified properties of the desired resource in the REST response.
A normal response from GET /profiles/123 would include all the properties of the resource as seen above. When the fields query param is included in the request, only the fields specified are returned. 'GET /propfiles/123?fields=surname,favColor' would return
{
"href":"https://host/profiles/123",
"surname":"Smith",
"favColor":"red"
}
expand - (45:53 in video) Query string parameter that instructs the server to flesh out the specified child resources in the result. Using our example, if you were to call GET /profiles/123?expand=socialNetworks you might receive something like
{
"href":"https://host/profiles/123",
"givenName":"Bob",
"surname":"Smith",
"gender":"male",
"favColor":"red",
"socialNetworks": {
"href":"https://host/socialNetworkMemberships?profileId=123",
"items": [
{
"href":"https://host/socialNetworkMemberships/abcde",
"siteName":"Facebook",
"profileUrl":"http://www.facebook.com/..."
},
...
]
}
}
So...in my opinion ServiceStack's best feature is that it makes sending, receiving and handling POCOs over HTTP super easy. How you set up the POCOs and what you do in between (within the 'Service') is up to you. Does SS have opinions? Yes. Do you have to agree with them? No. (But you probably should :))
I think expanding on something like below would get you close to how you want to handle your api. Probably not the best example of ServiceStack but the ServiceStack code/requirements are barely noticeable and don't get in your way (AppHost configure not shown). You could probably do something similar in other .NET Frameworks (MVC/Web API/etc) but, in my opinion, won't look as much like straight C#/.NET code as with ServiceStack.
Request classes
[Route("/Profiles/{Id}")]
public class Profiles
{
public int? Id { get; set; }
}
[Route("/SocialNetworks/{Id}")]
public class SocialNetworks
{
public int? Id { get; set; }
}
Base Response class
public class BaseResponse
{
protected virtual string hrefPath
{
get { return ""; }
}
public string Id { get; set; }
public string href { get { return hrefPath + Id; } }
}
Classes from example
public class Profile : BaseResponse
{
protected override string hrefPath { get { return "https://host/profiles/"; } }
public string GivenName { get; set; }
public string SurName { get; set; }
public string Gender { get; set; }
public string FavColor { get; set; }
public List<BaseResponse> SocialNetworks { get; set; }
}
public class SocialNetwork: BaseResponse
{
protected override string hrefPath { get { return "https://host/socialNetworkMemberships?profileId="; }}
public string SiteName { get; set; }
public string ProfileUrl { get; set; }
}
Services
public class ProfileService : Service
{
public object Get(Profiles request)
{
var testProfile = new Profile { Id= "123", GivenName = "Bob", SurName = "Smith", Gender = "Male", FavColor = "Red",
SocialNetworks = new List<BaseResponse>
{
new SocialNetwork { Id = "abcde", SiteName = "Facebook", ProfileUrl = "http://www.facebook.com/"}
}
};
if (!String.IsNullOrEmpty(this.Request.QueryString.Get("fields")) || !String.IsNullOrEmpty(this.Request.QueryString.Get("expand")))
return ServiceHelper.BuildResponseObject<Profile>(testProfile, this.Request.QueryString);
return testProfile;
}
}
public class SocialNetworkService : Service
{
public object Get(SocialNetworks request)
{
var testSocialNetwork = new SocialNetwork
{
Id = "abcde",
SiteName = "Facebook",
ProfileUrl = "http://www.facebook.com/"
};
if (!String.IsNullOrEmpty(this.Request.QueryString.Get("fields")) || !String.IsNullOrEmpty(this.Request.QueryString.Get("expand")))
return ServiceHelper.BuildResponseObject<SocialNetwork>(testSocialNetwork, this.Request.QueryString);
return testSocialNetwork;
}
}
Reflection Helper Class
public static class ServiceHelper
{
public static object BuildResponseObject<T>(T typedObject, NameValueCollection queryString) where T: BaseResponse
{
var newObject = new ExpandoObject() as IDictionary<string, object>;
newObject.Add("href", typedObject.href);
if (!String.IsNullOrEmpty(queryString.Get("fields")))
{
foreach (var propertyName in queryString.Get("fields").Split(',').ToList())
{
//could check for 'socialNetwork' and exclude if you wanted
newObject.Add(propertyName, typedObject.GetType().GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).GetValue(typedObject, null));
}
}
if (!String.IsNullOrEmpty(queryString.Get("expand")))
{
foreach (var propertyName in queryString.Get("expand").Split(',').ToList())
{
newObject.Add(propertyName, typedObject.GetType().GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).GetValue(typedObject, null));
}
}
return newObject;
}
}
Usually you can control the serialization of your DTOs by setting the DataMember attributes. With those attributes you can control if the property should have defaults or not.
Meaning if you simply do not define the property of the object you want to return, it should not be serialized and therefore will not be shown in the resulting Json.
ServiceStack internally uses the standard DataContract...Serializer, so this should be supported
Otherwise you could also make use of dynamic objects and simply compose your object at runtime, serialize it and send it back.
Here is a very very basic example:
var seri = JsonSerializer.Create(new JsonSerializerSettings() { });
using (var textWriter = new StringWriter())
{
var writer = new JsonTextWriter(textWriter);
dynamic item = new { Id = id };
seri.Serialize(writer, item);
return textWriter.ToString();
}

Example of how to use AutoFixture with NSubstitute

I use NSubstitute a lot. And I love it.
I am just looking into AutoFixture. It seems great!
I have seen AutoFixture for NSubstitute and seen a few examples in Moq on how to use this feature.
But I can't seem to translate it into NSubstitute.
I tried this:
var fixture = new Fixture().Customize(new AutoNSubstituteCustomization());
var addDest = Substitute.For<IPerson>();
Using:
public interface IPersonEntity
{
int ID { get; set; }
string FirstName { get; set;}
string LastName { get; set;}
DateTime DateOfBirth { get; set; }
char Gender { get; set; }
}
And I get an object, but none of the properties are populated (kind of the point of AutoFixture).
I also tried:
var fixture = new Fixture().Customize(new AutoNSubstituteCustomization());
var result = fixture.Create<IPersonEntity>();
That also gave me an object with no populated properties. (Note if I do the above with a PersonEntity class, then the properties are all populated.)
I am sure that there is a way to make this work, but I can't seem to find it.
So, given my IPersonEntity interface above, does anyone know how to use AutoFixture and NSubstitute to give me a populated IPersonEntity object?
Instead of customizing the Fixture instance with the AutoNSubstituteCustomization you may use the customization below:
var fixture = new Fixture().Customize(
new AutoPopulatedNSubstitutePropertiesCustomization());
var result = fixture.Create<IPersonEntity>();
// -> All properties should be populated now.
The AutoPopulatedNSubstitutePropertiesCustomization is defined as:
internal class AutoPopulatedNSubstitutePropertiesCustomization
: ICustomization
{
public void Customize(IFixture fixture)
{
fixture.ResidueCollectors.Add(
new Postprocessor(
new NSubstituteBuilder(
new MethodInvoker(
new NSubstituteMethodQuery())),
new AutoPropertiesCommand(
new PropertiesOnlySpecification())));
}
private class PropertiesOnlySpecification : IRequestSpecification
{
public bool IsSatisfiedBy(object request)
{
return request is PropertyInfo;
}
}
}
The difference with the AutoNSubstituteCustomization is that the above customization is also decorated with a Postprocessor instance to automatically set values for all the public properties of the requested type.
References:
The above solution is inspired by the following blog articles by Mark Seemann:
How to configure AutoMoq to set up all properties
How to automatically populate properties with AutoMoq
Though the other answer has been marked as correct back then, I just wanted to add for completeness that you can indeed use AutoNSubstituteCustomization:
var fixture = new Fixture().Customize(new AutoNSubstituteCustomization() { ConfigureMembers = true});
var result = fixture.Create<IPersonEntity>();
This will result in the properties being populated.

How to handle custom Properties in AutoMapper

I've got a ViewModel that takes some Model data and slightly alters it.
The way I'm doing it "works" since I just pass the DomainModel to the constructor for the ViewModel, but since I'm using AutoMapper on some of my one-to-one ViewModels, I thought I'd try and learn how to do the mapping across all ViewModels.
Here's an example of a ViewModel that does a little extra.
public class UsersDetailsViewModel
{
public string UserName { get; set; }
public string Email { get; set; }
public string Website { get; set; }
public int ID { get; set; }
public List<OpenID> OpenIds { get; set; }
public string UserAge { get; set; }
public string About { get; set; }
public string Slug { get; set; }
public System.DateTime LastSeen { get; set; }
public string Region { get; set; }
public string MemberSince { get; set; }
public string Reputation { get; set; }
public bool IsUserMatch { get; set; }
private readonly MarkdownDeep.Markdown _markdown;
public UsersDetailsViewModel(Domain.User user)
{
AuthUserData currentuser = AuthenticationHelper.RetrieveAuthUser;
_markdown.NoFollowLinks = true;
_markdown.SafeMode = true;
_markdown.ExtraMode = false;
_markdown.MarkdownInHtml = true;
// We want to ensure that the user has a username, even if they
// haven't set one yet. What this does is check to see if the
// user.UserName field is blank, and if it is, it will set the
// username to "UserNNNN" where NNNN is the user ID number.
_UserName = (user.UserName != null) ? user.UserName : "User" + user.ID.ToString;
// Nothing fancy going on here, we're just re-passing the object from
// the database to the View. No data manipulation!
_Email = user.Email;
_Website = user.WebSite;
_ID = user.ID;
// Get's a list of all of the user's OpenID's
_OpenIds = user.OpenIDs.ToList;
// Converts the users birthdate to an age representation
_UserAge = user.BirthDate.ToAge;
//IE: 29
// Because some people can be real ass holes and try to submit bad
// data (scripts and shitè) we have to modify the "About" content in
// order to sanitize it. At the same time, we transform the Markdown
// into valid HTML. The raw input is stored without sanitization in
// the database. this could mean Javascript injection, etc, so the
// output ALWAYS needs to be sanitized.
// This method below was used in conjunction with MarkDownSharp
// _About = Trim(Utilities.HtmlSanitizer.Sanitize(Markdown.Transform(user.About)))
_About = _markdown.Transform(user.About);
// Removes spaces from Usernames in order to properly display the
// username in the address bar
_Slug = Strings.Replace(user.UserName, " ", "-");
// Returns a boolean result if the current logged in user matches the
// details view of tBhe user in question. This is done so that we can
// show the edit button to logged in users.
_IsUserMatch = (currentuser.ID == user.ID);
// Grabs the users registration data and formats it to a <time> tag
// for use with the timeago jQuery plugin
_MemberSince = user.MemberSince;
// Grabs the users last activity and formats it to a <time> tag
// for use with the timeago jQuery plugin
_LastSeen = user.ActivityLogs.Reverse.FirstOrDefault.ActivityDate;
// Formats the users reputation to a comma Deliminated number
// IE: 19,000 or 123k
_Reputation = user.Reputation.ToShortHandNumber;
// Get the name of the users Default Region.
_Region = user.Region.Name.FirstOrDefault;
}
}
And here's how I currently utilize the above ViewModel
public ActionResult Details(int id)
{
User user = _userService.GetUserByID(id);
if (user != null) {
Domain.ViewModels.UsersDetailsViewModel userviewmodel = new Domain.ViewModels.UsersDetailsViewModel(user);
return View(userviewmodel);
} else {
// Because of RESTful URL's, some people will want to "hunt around"
// for other users by entering numbers into the address. We need to
// gracefully redirect them to a not found page if the user doesn't
// exist.
throw new ResourceNotFoundException();
}
}
How can I use (or should I use) AutoMapper to map my DomainModel to my ViewModel while doing the custom processing you see above?
On automapper where you create the Map you can specify additional processes for specific members of the destination type.
So where your default map would be
Mapper.Map<Domain.User, UsersDetailsViewModel>();
there is a fluent syntax to define the more complicated mappings:
Mapper.Map<Domain.User, UsersDetailsViewModel>()
.ForMember(vm=>vm.UserName, m=>m.MapFrom(u=>(u.UserName != null)
? u.UserName
: "User" + u.ID.ToString()));
Here the ForMember takes two Arguments the first defines the property that you are mapping to. The second provides a means of defining the mapping. For an example I have copped out and shown one of the easy mappings.
If you require a more difficult mapping, (such as your CurrentUser mapping) you can create a class that implements the IResolver interface, incorporate your mapping logic in that new clases and then add that into the mapping.
Mapper.Map<Domain.User, UsersDetailsViewModel>()
.ForMember(vm=>vm.IsUserMatch, m=>m.ResolveUsing<MatchingUserResolver>()));
when Mapper comes to do the mapping it will invoke your custom resolver.
Once you discover the syntax of the .ForMember method everything else kind of slots into place.
Custom mapping can be defined in global.ascx (at startup) by following codes :
AutoMapper.Mapper.CreateMap<Domain.User, UsersDetailsViewModel>()
.ForMember(o => o.Email, b => b.MapFrom(z => z.Email))
.ForMember(o => o.UserName , b => b.MapFrom(user => (user.UserName != null) ? user.UserName : "User" + user.ID.ToString));
you can do some initialization via BeforeMap () method. But you may need to do some changes in your viewmodel.
I think the syntax has slightly changed in 2019 (ASP.NET Core 2.2), this method is now handled with the MapperConfiguration and the static methods are no more available.
But I agree with #KJSR, this post is still really useful :-)
private Mapper UserMapper= new Mapper(new MapperConfiguration(cfg => (cfg.CreateMap<Domain.User, UsersDetailsViewModel>())
.ForMember(x=>x.Email, y=>y.MapFrom(z=>z.Email))
.ForMember(x => x.UserName , y => y.MapFrom(user => (user.UserName != null) ? user.UserName : "User" + user.ID.ToString))));

Categories

Resources