简体   繁体   English

如何在类库项目中配置自动映射器?

[英]How to configure Auto mapper in class library project?

I am using auto mapping first time.我第一次使用自动映射。

I am working on c# application and I want to use auto mapper.我正在开发 c# 应用程序,我想使用自动映射器。

(I just want to know how to use it, so I don't have asp.net app neither MVC app.) (我只是想知道如何使用它,所以我既没有 ASP.NET 应用程序,也没有 MVC 应用程序。)

I have three class library projects.我有三个类库项目。

在此处输入图片说明

I want to write transfer process in the service project.我想在服务项目中编写传输过程。

So I want to know how and where should I configure the Auto Mapper ?所以我想知道我应该如何以及在哪里配置 Auto Mapper ?

So based on Bruno's answer here and John Skeet's post about singletons I came up with the following solution to have this run only once and be completely isolated in class library unlike the accepted answer which relies on the consumer of the library to configure the mappings in the parent project:因此,基于 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...
    }
}

Then in your code where you need to map one object to another you can just do:然后在您需要将一个对象映射到另一个对象的代码中,您可以执行以下操作:

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

NOTE: This code is based on AutoMapper 6.2 and it might require some tweaking for older versions of AutoMapper.注意:此代码基于 AutoMapper 6.2,可能需要对旧版本的 AutoMapper 进行一些调整。

You can place the configuration anywhere:您可以将配置放在任何地方:

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()
    {
    ......
    }

But it has to be called by the application using the libraries at some point:但它必须在某些时候由应用程序使用库调用:

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

Nobody outside of your library has to configure AutoMapper图书馆外的任何人都不必配置 AutoMapper

I recommend that you use the instance based approach using an IMapper .我建议您使用IMapper使用基于实例的方法 That way no one outside your library has to call any configuration method.这样,您的库之外的任何人都不必调用任何配置方法。 You can define a MapperConfiguration and create the mapper from there all inside the class library.您可以在MapperConfiguration中定义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());

Marko's answer is correct.马尔科的回答是正确的。

We can also go by a below simple solution.我们也可以通过以下简单的解决方案。

 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>();
        });
    }
}
And we can use it like. 我们可以像这样使用它。
 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);

I have used the Patel Vishal's solution and customized it to my needs.我使用了 Patel Vishal 的解决方案并根据我的需要对其进行了定制。 It's a generic class which makes sure only one instance of mapping is saved in memory per object mapping.它是一个通用类,可确保每个对象映射仅在内存中保存一个映射实例。

  1. TModel - is a DTO object TModel - 是一个 DTO 对象
  2. TData - is a Database table object in Entity Framework TData - 是实体框架中的数据库表对象
  3. DTO.IBaseModel - is a base class for DTO object which has one property: ID DTO.IBaseModel - 是 DTO 对象的基类,它具有一个属性:ID
  4. IBaseModel - is a base class for the entity framework database entity with ID property only IBaseModel - 是仅具有 ID 属性的实体框架数据库实体的基类

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>();
        });
    }
}

I am using this class in a BaseService<TData, TModel> (Service/Repository pattern) as such:我在 BaseService<TData, TModel>(服务/存储库模式)中使用这个类,如下所示:

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

As you can see, it's a virtual method.如您所见,这是一个虚方法。 Mapping can be overwritten, if customization required by the inheriting Service.如果继承服务需要自定义,则可以覆盖映射。

I have come across this kind of requirement as well.我也遇到过这种需求。 What I have done in .Net 6.0 is, I create a library project and create the profile class:我在 .Net 6.0 中所做的是,我创建了一个库项目并创建了配置文件类:

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

while in the api or web project, I just create a child class to inherit from the profile above, and register it in startup.cs services.AddAutoMapper(typeof(Startup));.而在 api 或 web 项目中,我只是创建了一个子类来继承上面的配置文件,并在 startup.cs services.AddAutoMapper(typeof(Startup)); 中注册它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM