Giter Site home page Giter Site logo

automapper.attributes's Introduction

AutoMapper now supports attributes natively. Don't use this library. More documentation here: https://docs.automapper.org/en/stable/Attribute-mapping.html

I also wrote about my experience writing this library here.

AutoMapper.Attributes

A convenient way to create AutoMapper type mappings using attributes.

Build status Nuget

Why use AutoMapper.Attributes?

  • Self-documenting code - mappings become more obvious to developers since they are attached directly to the type
  • Simple, intuitive API for mapping objects
  • Allows for dot notation of mapping properties
  • Works with AutoMapper 5+ (including 6)

How to use

  1. Create the classes you'd like to map.
  2. Add the [MapsTo] attribute to the source class, with the target type as the argument. (Alternatively, you can use the [MapsFrom] attribute to map the target class with the source type.)
  3. Call the MapTypes() extension method on the assembly from which you want to map your types when you call Mapper.Initialize.
  4. You're done!

Sample

public class Program
{
    public void Main()
    {
        AutoMapper.Mapper.Initialize(config => {
            typeof(Program).Assembly.MapTypes(config);      //or use typeof(Program).GetTypeInfo().Assembly if using .NET Standard
        });
        
        var person = new Person { FirstName = "John", LastName = "Lackey" };
        var customer = AutoMapper.Mapper.Map<Customer>(person);
        
        Console.WriteLine(customer.LastName);
        // Output: Lackey
    }

    [MapsTo(typeof(Customer))]
    public class Person 
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Notes { get; set; }
    }

    public class Customer
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string MyCustomerNotes { get; set; }
    }
}

Mapping properties

AutoMapper's built-in property mapping works for 90% of use cases. But what if you need to map two properties with different names, or even a property that is a few classes deep? There are two attributes made for this - [MapsFromProperty] and [MapsToProperty]. Both take a type and a name of a property you want to map from/to. These attributes support nested property mapping using dot notation.

[MapsFromProperty(typeof(SourceType), "Address.City")]

MapsToProperty example

[MapsToProperty] allows you to designate a source type's property as mapping to a target type's property. Simply:

  1. Define your source class (in this example, Person)
  2. Define your target class (in this example, Customer)
  3. Define your source class properties
  4. Add the [MapsToProperty] to the property that you want to map to the target property. In this case, the attribute's arguments are the target type and the name of the target type's property.
Sample
public class Program
{
    public void Main()
    {
        AutoMapper.Mapper.Initialize(config => {
            typeof(Program).Assembly.MapTypes(config);
        });

        var person = new Person { Notes = "these are some notes" };
        var customer = AutoMapper.Mapper.Map<Customer>(person);
        
        Console.WriteLine(customer.MyCustomerNotes);
        // Output: these are some notes
    }

    [MapsTo(typeof(Customer))]
    public class Person 
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        [MapsToProperty(typeof(Customer), "MyCustomerNotes")]
        public string Notes { get; set; }
    }

    public class Customer
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string MyCustomerNotes { get; set; }
    }
}

MapsFromProperty example

[MapsFromProperty] allows you to designate a target type's property as mapping to a source type's property. Simply:

  1. Define your source class (in this example, Person)
  2. Define your target class (in this example, Customer)
  3. Define your source class properties
  4. Add the [MapsFromProperty] to the target type's property that you want to map to the source property. In this case, the attribute's arguments are the source type and the name of the source type's property.
Sample
public class Program
{
    public void Main()
    {
        AutoMapper.Mapper.Initialize(config => {
            typeof(Program).Assembly.MapTypes(config);
        });

        var person = new Person { Notes = "these are some more notes" };
        var customer = AutoMapper.Mapper.Map<Customer>(person);
        
        Console.WriteLine(customer.MyCustomerNotes);
        // Output: these are some more notes
    }

    public class Person 
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Notes { get; set; }
    }

    [MapsFrom(typeof(Person))]
    public class Customer
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        [MapsFromProperty(typeof(Person), "Notes")]
        public string MyCustomerNotes { get; set; }
    }
}

Two-way mapping

Use [MapsToAndFromProperty] to tell the mapper to bind the source type's property to the target type's property and back.

  1. Define your source class (in this example, Person)
  2. Define your target class (in this example, Customer)
  3. Define your source class properties
  4. Add the [MapsFromProperty] to the source or target type's property that you want to map to the other type's property.

Ignoring properties

You can use the following attributes to ignore properties on a target type or a source type.

IgnoreMapFrom

Use the [IgnoreMapFrom] attribute on a target type's property to ignore all properties from the source type.

Sample
public class Person 
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Notes { get; set; }
}

[MapsFrom(typeof(Person))]
public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    [IgnoreMapFrom(typeof(Person))]     //Notes will not be set from type Person
    public string Notes { get; set; }
}

IgnoreMapToProperties

Use the [IgnoreMapToProperties] attribute on your source type to ignore one or more properties on the target type. This must be added to the type itself and cannot be added to properties due to a limitation of AutoMapper - see: AutoMapper/AutoMapper#1556

Sample
//Notes and Costs will not 
[IgnoreMapToProperties(typeof(Customer), nameof(Customer.Notes), nameof(Customer.Costs))]
public class Person 
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Notes { get; set; }
    public decimal Costs { get; set; }
}

[MapsFrom(typeof(Person))]
public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Notes { get; set; }
    public decimal Costs { get; set; }    
}

Ok, but I need some super custom mapping behavior.

No problem - you can create a subclass of MapsToAttribute and add a method called ConfigureMapping method with the type arguments specified explicitly for IMappingExpression. As long as the method is named ConfigureMapping (case sensitive!) and the method signature uses the exact same type arguments as the classes you're mapping, you can configure the mapping to your heart's content:

public class MapsToCustomer : MapsToAttribute
{
    public MapsToCustomer() : base(typeof(Customer)) {}

    public void ConfigureMapping(IMappingExpression<Person, Customer> mappingExpression)
    {
        mappingExpression.ForMember(d => d.CustomerNotes, expression => expression.MapFrom(s => s.Notes));
    }
}

What else you got?

  • The examples above make heavy use of the [MapsTo] attribute, but don't forget you have a [MapsFrom] attribute as well!
  • You can set the ReverseMap property in the [MapsTo]/[MapsFrom] attribute to true if you want to map the classes in reverse as well, like this:
[MapsTo(typeof(Customer), ReverseMap = true)]    //this will map Customer to Person and Person to Customer
public class Person {...}

License

This project is licensed under the MIT license.

Author info

Made with <3 by Spencer Schneidenbach

Twitter @schneidenbach
Website https://schneids.net

automapper.attributes's People

Contributors

ryanherbert avatar schneidenbach avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

automapper.attributes's Issues

ReverseMap

Hi,

Fantastic package :) One issue though, the ReverseMap doesn't work as explained in the documentation.
It states :
"You can set the ReverseMap property in the [MapsTo]/[MapsFrom] attribute to true if you want to map the classes in reverse as well, like this:
[MapsTo(typeof(Customer), true)] //this will map Customer to Person and Person to Customer"

But since ReverseMap is not an argument of the MapsToAttribute constructor, this doesn't work. Can be circumenvented by setting it via a named parameter, ie.:
[MapsTo(typeof(Customer), ReverseMap = true)]

Maybe add an optional parameter to the constructor ?

Kind regards,
Sven.

Support For .NetStandard,Version=v1.6 ?

Hi,

Thanks for all your works but sadly, i've come to notice that this nuget package does not support .NetStandard v1.6. Are there any plans to support it?

Thank you in advance.

Using two MapsFromAttribute on both base and inherited class ruins the latter's mappings.

PasteBin: https://pastebin.com/nGYL300T

The repro above shows a weird bug in the system:

When we have class B inherited from class A, and both are decorated with independent MapsFrom attributes with appropriate ConfigureMapping methods, the B's class mappings are ignored for some reason.

The method ConfigureMapping on the B's attribute is actually ran, but is ignored and the Mapper.Map produces a result which we would expect to be when the ConfigureMapping method would not exist at all - so the custom mappings are gone.

If we remove the custom MapsFrom attribute from the A class, however, the bug does not appear.
If we manually set the custom mapping to B (via Mapper.CreateMap), the bug does not appear.

.NET Core 2

The following code does not work on a Console app target framework .NET Core 2.0

public static void Main()
{
    AutoMapper.Mapper.Initialize(config => {
        typeof(Program).Assembly.MapTypes(config);
    });

    var person = new Person { Notes = "these are some notes" };
    var customer = AutoMapper.Mapper.Map<Customer>(person);

    Console.WriteLine(customer.MyCustomerNotes);
    Console.ReadLine();
    // Output: these are some notes
}

[MapsTo(typeof(Customer))]
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    [MapsToProperty(typeof(Customer), "MyCustomerNotes")]
    public string Notes { get; set; }
}

public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string MyCustomerNotes { get; set; }
}

W‍‍‍‍‍‍‍‍‍e currently fix it but changing the target framework to netcoreapp2.0

  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>

That'd be great if we have that core2 compatibility in the official release.

Mapping a Collection of objects

I'm trying to map a List of Users to a List of Contact.

Is there anything special that needs to happen for this to work?

The attempted mapping...

var contacts = AutoMapper.Mapper.Map<List<Users>>(userList);

The target class...

using AutoMapper.Attributes;
using NS.Models.Context;

namespace NS.Models
{
    [MapsFrom(typeof(Users))]
    public class Contact
    {
        [MapsFromProperty(typeof(Users), "DepartmentObj.Department")]
        public string department { get; set; }

        [MapsFromProperty(typeof(Users), "Email")]
        public string emailAddress { get; set; }

        [MapsFromProperty(typeof(Users), "First")]
        public string firstName { get; set; }

        [MapsFromProperty(typeof(Users), "Last")]
        public string lastName { get; set; }

        [MapsFromProperty(typeof(Users), "Cellnumber")]
        public string telephoneMobile { get; set; }

        [MapsFromProperty(typeof(Users), "Extension")]
        public string telephoneOffice { get; set; }

        [IgnoreMapFrom(typeof(Users))]

        public Photo photo { get; set; }
    }
}

contacts ends up equaling userList seemingly without modification.

IgnoreMapFrom doesn't pass mapping validation

The following test correctly fails:

public class Foo
{
    public string Bar { get; set; }
}

[MapsFrom(typeof(Foo))]
public class Qux
{
    public string Bar { get; set; }

    public string Baz { get; set; }
}

public class IgnoredPropertyTests
{
    [Fact]
    public void IgnoredPropertyYieldsValidMapping()
    {
        var config = new MapperConfiguration(cfg =>
        {
            typeof(Foo).GetTypeInfo().Assembly.MapTypes(cfg);
        });
        config.AssertConfigurationIsValid();
    }
}

To fix the test, I can add [IgnoreMap] to Baz. However, I cannot add [IgnoreMapFrom(typeof(Foo))] - despite that attribute, the mapping validation still fails. Is that the intended behavior, or a bug?

net45 actually targets 452

using nuget package with plain framework 4.5 doesn't work, looks dll dargets 452 anyway.
this is true for 5.0.1 (single dll targets 4.5) but also for previous 5.0.0 (both dll targets 4.5.2)

MapsFromPropertyAttribute with targetType

I have two classes inheriting from the same interface. Both contain an property of list with shared interface type. To use AutoMapper I need to explicitly tell it to use a different target type, instead of the shared inherited interface created by the source type.

Let me explain better with some code:

interface IFace {
  String Prop { get; set; }
  IEnumerable<IListItemFace> List { get; set; }
}
class Source : IFace {
  String Prop { get; set; }
  IEnumerable<IListItemFace> List { get; set; }
}
[MapsFrom(typeof(IFace))]
class Target : IFace {
  String Prop { get; set; }
  [MapsFromProperty(typeof(IEnumerable<ListItemTarget>), "List")]
  IEnumerable<IListItemFace> List { get; set; }
}

interface IListItemFace {
  String Prop2 { get; set; }
}
class ListItemSource : IListItemFace {
  String Prop2 { get; set; }
}
[MapsFrom(typeof(IListItemFace))]
class ListItemTarget : IListItemFace {
  String Prop2 { get; set; }
}

Note: I don't have access to Source & ListItemSource or their interfaces.

Now I call AutoMapper with:

IFace x = new Source { Prop = "Hoi", List = new List<ListItemSource> };
Target y = Mapper.Map<Target>(x);
IEnumerable<ListItemTarget> z = y.List;  // <-- this will throw, as it can't convert source type to target type.

I hoped using MapsFromPropertyAttribute on Target.List solved this issue, but I need to explicitly set the target type.

So, now my question; would it possible to create an overload to MapsFromProperty with an target type variable.

P.s. The following solution did solved my problem, but it requires all properties with the same structure to be mapped manually:

public class MapsFromTarget : MapsFromAttribute {
  public MapsFromTarget() : base(typeof(IFace)) { }
  public void ConfigureMapping(IMappingExpression<IFace, Target> mappingExpression) {
      mappingExpression.ForMember(
        destinationMember => destinationMember.List,
        memberOptions => memberOptions.MapFrom(
          sourceMember => Mapper.Map<IEnumerable<Target>>(sourceMember.List)));
  }
}

.NET Core 2 Compatibility

Trying to use this with a .NET Core 2 project, however, the examples do not work. I'm currently working on a solution, but figured i'd put this on here to see if you have any insight while I work on it.

The type or namespace name 'MapsToProperty' could not be found

Hi,

I have added AutoMapper.Attributes using NuGet package and when building I am getting following error:

The type or namespace name 'MapsToProperty' could not be found (are you missing a using directive or an assembly reference?)

I can see the AutoMapper.Attributes in bin folder.
I am using .Net 4.5.1

Please help.

Regards,
Dilhan

Open Generics with ConvertUsing

Hi,

How can I achieve the same functionality as open generic with convert using from the Automapper.Attributes?

Thanks,
Attiqe

Add support for MapFromProperty Lambda expressions

It'd be great if AutoMapper.Attributes supported mapping using Lambda expressions like regular AutoMapper does. Mapping using Attributes appears to break down when I get into mapping values from structs attached to properties, whereas the regular AutoMapper works fine with this when using Lambda expressions.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.