如何在类库项目中配置AutoMapper?

42

我第一次使用自动映射。

我正在开发C#应用程序,想要使用Auto Mapper。

(我只是想知道如何使用它,因此我没有ASP.NET应用程序,也没有MVC应用程序。)

我有三个类库项目。

enter image description here

我想在服务项目中编写转换过程。

因此,我想知道在哪里以及如何配置Auto Mapper?

6个回答

65
所以基于Bruno在这里的回答和John Skeet有关单例模式的文章,我想出了以下解决方案,使其仅运行一次并完全隔离于类库中,而不像被接受的答案依赖于库的使用者来配置父项目中的映射:
public static class Mapping
{
    private static readonly Lazy<IMapper> Lazy = new Lazy<IMapper>(() =>
    {
        var config = new MapperConfiguration(cfg => {
            // This line ensures that internal properties are also mapped over.
            cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
            cfg.AddProfile<MappingProfile>();
        });
        var mapper = config.CreateMapper();
        return mapper;
    });

    public static IMapper Mapper => Lazy.Value;
}

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Source, Destination>();
        // Additional mappings here...
    }
}

那么在你的代码中,当你需要将一个对象映射到另一个对象时,你只需要这样做:

var destination = Mapping.Mapper.Map<Destination>(yourSourceInstance);

注意:此代码基于AutoMapper 6.2,对于旧版本的AutoMapper可能需要进行微调。


4
谢谢。这是最好的答案,因为它不依赖于其他任何东西,只依赖于自身。 - Ebbelink
1
这是一个自包含的解决方案,可以用于任何类型的应用程序,而不仅仅是类库。谢谢,@Marko。 - Alex
我应该在哪里编写这段代码?在父项目还是类库项目中? - Ali.Rashidi
@Ali.Rashidi 类库项目啊。这正是将其隔离在类库中的全部意义,只要引用该类库,它就可以在任何地方工作。 - Marko

29

您可以在任何地方放置配置:

public class AutoMapperConfiguration
{
    public static void Configure()
    {
        Mapper.Initialize(x =>
            {
                x.AddProfile<MyMappings>();              
            });
    }
}

 public class MyMappings : Profile
{
    public override string ProfileName
    {
        get { return "MyMappings"; }
    }

    protected override void Configure()
    {
    ......
    }

但是应用程序必须在某个时刻使用库来调用它:

void Application_Start()
    {               
        AutoMapperConfiguration.Configure();
    }

8

没有使用你的库的人需要配置AutoMapper

我建议您使用基于实例的方法,使用IMapper。这样,除了你的库之外的任何人都不需要调用任何配置方法。您可以在类库内定义一个MapperConfiguration并从中创建映射器。

var config = new MapperConfiguration(cfg => {
    cfg.AddProfile<AppProfile>();
    cfg.CreateMap<Source, Dest>();
});

IMapper mapper = config.CreateMapper();
// or
IMapper mapper = new Mapper(config);
var dest = mapper.Map<Source, Dest>(new Source());

2
我们应该把这段代码放在类库的哪里,以便它自动调用(仅一次)? - soccer7
@kamalpreet 可能是在类的静态构造函数中。或者看一下Marko的答案 - Bruno Zell

3

Marko的答案是正确的。

我们还可以通过以下简单解决方案来处理。

 public static class ObjectMapper
{
    public static IMapper Mapper
    {
        get
        {
            return AutoMapper.Mapper.Instance;
        }
    }
    static ObjectMapper()
    {
        CreateMap();
    }
    private static void CreateMap()
    {
        AutoMapper.Mapper.Initialize(cfg =>
        {
            cfg.CreateMap<SourceClass, DestinationClass>();
        });
    }
}

public class SourceClass
{
    public string Name { get; set; }
}
public class DestinationClass
{
    public string Name { get; set; }
}
SourceClass c1 = new SourceClass() { Name = "Mr.Ram" };

DestinationClass c2 = ObjectMapper.Mapper.Map<DestinationClass>(c1);

0

我也遇到过这种需求。在 .Net 6.0 中,我创建了一个库项目并创建了配置类:

public class AutoMapperProfile : Profile
{
    public AutoMapperProfile()
    {
        CreateMap<Entity, Dto>();
        CreateMap<Dto, Entity>();
        ......
    }
}

在 API 或 Web 项目中,我只需创建一个子类来继承上面的配置文件,并在 startup.cs 的 services.AddAutoMapper(typeof(Startup)) 中进行注册。


0

我使用了Patel Vishal的解决方案,并根据我的需求进行了定制。 这是一个通用类,确保每个对象映射在内存中只保存一个映射实例。

  1. TModel - 是DTO对象
  2. TData - 是Entity Framework中的数据库表对象
  3. DTO.IBaseModel - 是DTO对象的基类,它有一个属性:ID
  4. IBaseModel - 是仅具有ID属性的Entity Framework数据库实体的基类

public static class ObjectMapper<TModel, TData>
    where TModel : class, DTO.IBaseModel, new() 
    where TData : class, IBaseModel, new()
{
    private static readonly MapperConfiguration _mapperConfiguration;
    public static IMapper Mapper => new Mapper(_mapperConfiguration);

    static ObjectMapper()
    {
        _mapperConfiguration ??= CreateMap();
    }

    private static MapperConfiguration CreateMap()
    {
        return new (cfg =>
        {
            cfg.CreateMap<TData, TModel>();
        });
    }
}

我正在一个BaseService<TData, TModel>(服务/仓储模式)中使用这个类:

    public virtual TModel Convert(TData t)
    {
        return ObjectMapper<TModel, TData>.Mapper.Map<TModel>(t);
    }

正如您所见,这是一个虚方法。如果继承服务需要自定义,映射可以被覆盖。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接