.net core 3.1 WebAPi 使用 AutoMapper 9.0、10.0
阅读原文时间:2023年07月09日阅读:1

AutoMapper 可以很方便完成数据对象之间的转换。

Dto -> Entity

Entity -> ViewModel

Step 1:通过 NuGet 安装 AutoMapper 的包。

netcoreapp3.1

Project.csproj

准备两个类 User 和 Department

public class User  
{  
    public int Id { get; set; }

    public string Name { get; set; }

    public int Age { get; set; }

    public string Remark { get; set; }

    public int DepartmentId { get; set; }

    public Department DepartmentInfo { get; set; }  
}

User

public class Department  
{  
    public int Id { get; set; }

    public string Name { get; set; }

    public string Remark { get; set; }  
}

Department

创建 User 的 Dto 和 ViewModel

public class UserDto  
{  
    public int Id { get; set; }

    public string Name { get; set; }  
}

UserDto

public class UserViewModel  
{  
    public int Id { get; set; }

    public string Name { get; set; }

    public int Age { get; set; }

    public string Remark { get; set; }

    public int DepartmentId { get; set; }

    public string DepartmentName { get; set; }  
}

UserViewModel

Step 2:配置好对象之间的转换。

创建类 UserMapper 继承抽象类 Profile

public class UserMapper : Profile  
{  
    public UserMapper()  
    {  
        CreateMap<UserDto, User>();  
        CreateMap<User, UserViewModel>()  
            .BeforeMap((u, v) => u.Remark = "Good")  
            .ForMember(v => v.DepartmentId, u => u.MapFrom(user => user.DepartmentId))  
            .ForMember(v => v.DepartmentName, u => u.MapFrom(user => user.DepartmentInfo.Name))  
            .AfterMap((u, v) => u.Age++);  
    }  
}

UserMapper

Profile 里面实现了两个接口

Step 3:注册服务

在 Startup.cs 的 ConfigureServices 方法中注册。

    public void ConfigureServices(IServiceCollection services)  
    {  
        // ...  
        services.AddAutoMapper(typeof(UserMapper));  
        // ...  
    }    

ConfigureServices

Step 4:使用

创建 api 控制器

声明 private readonly IMapper _mapper;

\[Route("api/\[controller\]/\[action\]")\]  
\[ApiController\]  
public class UserController : ControllerBase  
{  
    private readonly IMapper \_mapper;

    public UserController(IMapper mapper)  
    {  
        \_mapper = mapper;  
    }

    \[ActionName("dto")\]  
    \[HttpGet\]  
    public IActionResult DtoToEntity()  
    {  
        var userDto = new UserDto() { Id = 1, Name = "Bill" };  
        var userEntity = \_mapper.Map<UserDto, User>(userDto);

        JsonResult result = new JsonResult(userEntity);  
        return result;  
    }

    \[ActionName("vo")\]  
    \[HttpGet\]  
    public IActionResult EntityToViewModel()  
    {  
        var department = new Department() { Id = 101, Name = "Market" };  
        var user = new User() { Id = 1, Name = "Bill", Age = 25, DepartmentId = 101, DepartmentInfo = department };  
        var viewModel = \_mapper.Map<User, UserViewModel>(user);

        JsonResult result = new JsonResult(viewModel);  
        return result;  
    }

}

UserController

结果:

Dto -> Entity

Entity -> ViewModel

Step 5:自动化注册

如果每添加一个 Mapper 都需要修改 StartUp 类来完成注册,不是什么好方式。

自动化注册才是更好的(主要还是方便摸鱼)。

为了实现自动化注册,需要找到项目中的所有 Mapper 对象,要给 Mapper 打上一个标记。

添加接口类 IProfile

public interface IProfile  
{

}

IProfile

在所有的 Mapper 类里面,实现这个接口。

public class UserMapper : Profile, IProfile  
{  
    public UserMapper()  
    {  
        CreateMap<UserDto, User>();  
        CreateMap<User, UserViewModel>()  
            .BeforeMap((u, v) => u.Remark = "Good")  
            .ForMember(v => v.DepartmentId, u => u.MapFrom(user => user.DepartmentId))  
            .ForMember(v => v.DepartmentName, u => u.MapFrom(user => user.DepartmentInfo.Name))  
            .AfterMap((u, v) => u.Age++);  
    }  
}

UserMapper

再通过查找所有实现了 IProfile 接口的类,就可以找到所有的 Mapper 对象。

( Profile 是 AutoMapper 组件里的接口,必须自定义项目中的唯一标记。)

创建 MapperRegister 类,实现获取所有的 Mapper 对象。

public class MapperRegister  
{  
    /// <summary>  
    /// 通过反射自动化注册  
    /// </summary>  
    /// <returns></returns>  
    public static Type\[\] MapType()  
    {

        Assembly ass = Assembly.GetAssembly(typeof(IProfile));  
        Type\[\] types = ass.GetTypes();

        List<Type> allList = new List<Type>();

        foreach (Type item in types)  
        {  
            if (item.IsInterface) continue;//判断是否是接口  
            Type\[\] ins = item.GetInterfaces();  
            foreach (Type ty in ins)  
            {  
                if (ty == typeof(IProfile))  
                {  
                    allList.Add(item);  
                }  
            }  
        }

        Type\[\] alltypes = allList.ToArray();  
        return alltypes;  
    }

}

MapperRegister

修改 StrartUp 类,调整注册方式。

    public void ConfigureServices(IServiceCollection services)  
    {  
        services.AddControllers();

        //services.AddAutoMapper(typeof(UserMapper));  
        //自动化注册  
        services.AddAutoMapper(MapperRegister.MapType());

    }

Startup

这样就可以每次添加 Mapper 类的时候,只需要添加 IProfile 标记,就可以自动注册了。

自动化注册方式二

在很多常见的项目中,同一个项目的Mapper文件都是放在同一个文件夹内。命名都以 Mapper 结尾。

然后在 Startup.cs 里面

        services.AddAutoMapper(  
            Assembly.Load("Leaf.Application").GetTypes()  
                .Where(t => t.FullName.EndsWith("Mapper"))  
                .ToArray()  
        );    

Assembly.Load() 里面传的是当前项目的名称,或者类库的名称。获取当前项目下的所有类文件。

通过 Lamda 表达式 Where 找到所有以 Mapper 结尾的文件。

这样就可以自动注册项目内的所有 Mapper 文件了。

摸鱼又更进了一步。

AutoMapper 配合强类型字段的 ORM 特别好用。比如 EF 。

入参控制好 Add 的 Dto。

返回参数 控制好 ViewModel。

这些文件都可以从数据库 Entity 对象里面复制,不需要手写字段。

无论多长的字段,都可以通过 Ctrl + C 和 Ctrl + V 来创建对应的 Dto 和 ViewModel 。

再通过 AutoMapper 的转换。

做 CURD 接口的时候,不需要写任何 Entity 里已存在的字段。

然后就可以愉快地上班摸鱼了。