Cách thiết lập Automapper trong ASP.NET Core


255

Tôi còn khá mới ở .NET và tôi quyết định giải quyết .NET Core thay vì học "những cách cũ". Tôi đã tìm thấy một bài viết chi tiết về việc thiết lập AutoMapper cho .NET Core ở đây , nhưng có một hướng dẫn đơn giản hơn cho người mới không?



Để biết các phiên bản lõi mới hơn (> v1), hãy xem câu trả lời của @ Saineshwar stackoverflow.com/a/53455699/833878
Robbie

1
Một câu trả lời hoàn chỉnh với một ví dụ nhấp vào liên kết này
Iman Bahrampour

Câu trả lời:


554

Tôi đã hiểu rồi! Dưới đây là chi tiết:

  1. Thêm Gói AutoMapper chính vào giải pháp của bạn thông qua NuGet .
  2. Thêm gói tiêm phụ thuộc AutoMapper vào giải pháp của bạn thông qua NuGet .

  3. Tạo một lớp mới cho một hồ sơ ánh xạ. (Tôi đã tạo một lớp trong thư mục giải pháp chính được gọi MappingProfile.csvà thêm mã sau đây.) Tôi sẽ sử dụng một UserUserDtođối tượng làm ví dụ.

    public class MappingProfile : Profile {
        public MappingProfile() {
            // Add as many of these lines as you need to map your objects
            CreateMap<User, UserDto>();
            CreateMap<UserDto, User>();
        }
    }
  4. Sau đó thêm AutoMapperConfiguration vào Startup.csnhư dưới đây:

    public void ConfigureServices(IServiceCollection services) {
        // .... Ignore code before this
    
       // Auto Mapper Configurations
        var mappingConfig = new MapperConfiguration(mc =>
        {
            mc.AddProfile(new MappingProfile());
        });
    
        IMapper mapper = mappingConfig.CreateMapper();
        services.AddSingleton(mapper);
    
        services.AddMvc();
    
    }
  5. Để gọi đối tượng được ánh xạ trong mã, hãy làm như sau:

    public class UserController : Controller {
    
        // Create a field to store the mapper object
        private readonly IMapper _mapper;
    
        // Assign the object in the constructor for dependency injection
        public UserController(IMapper mapper) {
            _mapper = mapper;
        }
    
        public async Task<IActionResult> Edit(string id) {
    
            // Instantiate source object
            // (Get it from the database or whatever your code calls for)
            var user = await _context.Users
                .SingleOrDefaultAsync(u => u.Id == id);
    
            // Instantiate the mapped data transfer object
            // using the mapper you stored in the private field.
            // The type of the source object is the first type argument
            // and the type of the destination is the second.
            // Pass the source object you just instantiated above
            // as the argument to the _mapper.Map<>() method.
            var model = _mapper.Map<UserDto>(user);
    
            // .... Do whatever you want after that!
        }
    }

Tôi hy vọng điều này sẽ giúp ai đó bắt đầu mới với ASP.NET Core! Tôi hoan nghênh mọi phản hồi hoặc chỉ trích vì tôi vẫn chưa quen với thế giới .NET!


3
Bài viết chi tiết được liên kết, Lostechies.com/jimmybogard/2016/07/20/ , giải thích cách Profilecác lớp học được định vị
Kieren Johnstone

22
@theutz Bạn cũng có thể hợp nhất hai dòng CreatMap đó với .ReverseMap () ở cuối, một trong hai. Có thể nhận xét nó, nhưng tôi thấy nó trực quan hơn.
Astravagrant

6
Có thể hữu ích ở Bước 3 để đề cập đến việc thêm "bằng cách sử dụng AutoMapper;" ở trên cùng để phương thức mở rộng được nhập.
Rocklan

8
Điều này hoạt động tốt với .net core 1.1, không còn nữa khi tôi nâng cấp lên .net core 2.0. Tôi nghĩ rằng, tôi cần xác định rõ ràng việc tập hợp lớp hồ sơ logic. Vẫn đang nghiên cứu làm thế nào để thực hiện điều đó. Cập nhật: Ah câu trả lời nằm trong bình luận của bạn, tôi phải vượt qua lớp typeof là hồ sơ của tôi. // services.AddAutoMapper (typeof (Khởi động)); // <- phiên bản máy tự động mới hơn sử dụng chữ ký này
Esen

3
Trong AutoMapper v8 và Dependency Injection v5 được thêm vào, điều duy nhất cần thiết là các dịch vụ.AddAutoMapper (); trong phương thức ConfigureService của lớp Startup. Đối với tôi, nó thậm chí có thể tìm thấy các lớp Hồ sơ trong các dự án thư viện lớp phụ thuộc.
stricq

68

Bước để sử dụng AutoMapper với ASP.NET Core.

Bước 1. Cài đặt AutoMapper.Extensions.Microsoft.DependencyInjection từ Gói NuGet.

nhập mô tả hình ảnh ở đây

Bước 2. Tạo một Thư mục trong Giải pháp để giữ các ánh xạ với Tên "Ánh xạ".

nhập mô tả hình ảnh ở đây

Bước 3. Sau khi thêm thư mục Ánh xạ, chúng tôi đã thêm một lớp có Tên " MappingProfile ", tên này có thể là bất cứ điều gì độc đáo và tốt để hiểu.

Trong lớp học này, chúng tôi sẽ duy trì tất cả các ánh xạ.

nhập mô tả hình ảnh ở đây

Bước 4. Khởi tạo Mapper khi khởi động "ConfigureService"

Trong Lớp Khởi động, chúng tôi cần Khởi tạo Hồ sơ mà chúng tôi đã tạo và Đăng ký Dịch vụ AutoMapper.

  Mapper.Initialize(cfg => cfg.AddProfile<MappingProfile>());

  services.AddAutoMapper();

Đoạn mã để hiển thị Phương thức ConfigureService nơi chúng tôi cần Khởi tạo và Đăng ký AutoMapper.

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }


    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });


        // Start Registering and Initializing AutoMapper

        Mapper.Initialize(cfg => cfg.AddProfile<MappingProfile>());
        services.AddAutoMapper();

        // End Registering and Initializing AutoMapper

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    }}

Bước 5. Nhận đầu ra.

Để có được kết quả đã ánh xạ, chúng ta cần gọi AutoMapper.Mapper.Map và vượt qua Điểm đến và Nguồn thích hợp.

AutoMapper.Mapper.Map<Destination>(source);

CodeSnippet

    [HttpPost]
    public void Post([FromBody] SchemeMasterViewModel schemeMaster)
    {
        if (ModelState.IsValid)
        {
            var mappedresult = AutoMapper.Mapper.Map<SchemeMaster>(schemeMaster);
        }
    }

13
Tôi nhận được lỗi sau : 'Mapper' does not contain a definition for 'initialize'. Tôi đang sử dụng AutoMapper.Extensions.Microsoft.DependencyInjectionphiên bản 7.0.0
kimbaudi

Câu trả lời siêu chi tiết. Cảm ơn ngài.
Rod Hartzell

1
nếu bạn đang sử dụng ASP.NET CORE 3.0, hãy kiểm tra hướng dẫn này Cách thiết lập AutoMapper trong ASP.NET Core 3.0 tutexchange.com/how-to-set-up-automapper-in-asp-net-core-3-0
Saineshwar

44

Tôi muốn mở rộng câu trả lời của @ theutz - cụ thể là dòng này:

// services.AddAutoMapper(typeof(Startup));  // <-- newer automapper version uses this signature.

Có một lỗi ( có thể ) trong AutoMapper.Extensions.Microsoft.DependencyInjection phiên bản 3.2.0. (Tôi đang sử dụng .NET Core 2.0)

Này được giải quyết trong này vấn đề GitHub. Nếu các lớp của bạn kế thừa lớp Hồ sơ của AutoMapper tồn tại bên ngoài hội đồng nơi lớp Khởi động của bạn có thể sẽ không được đăng ký nếu phép tiêm AutoMapper của bạn trông như thế này:

services.AddAutoMapper();

trừ khi bạn chỉ định rõ ràng tập hợp nào để tìm kiếm cấu hình AutoMapper.

Nó có thể được thực hiện như thế này trong Startup.ConfigureService của bạn:

services.AddAutoMapper(<assembies> or <type_in_assemblies>);

trong đó "hội đồng""type_in_assemblies" trỏ đến hội đồng nơi các lớp Hồ sơ trong ứng dụng của bạn được chỉ định. Ví dụ:

services.AddAutoMapper(typeof(ProfileInOtherAssembly), typeof(ProfileInYetAnotherAssembly));

Tôi cho rằng (và tôi nhấn mạnh vào từ này) rằng do việc thực hiện quá tải không tham số (mã nguồn từ GitHub ):

public static IServiceCollection AddAutoMapper(this IServiceCollection services)
{
     return services.AddAutoMapper(null, AppDomain.CurrentDomain.GetAssemblies());
}

chúng tôi dựa vào CLR đã lắp ráp JITed có chứa các cấu hình AutoMapper có thể đúng hoặc có thể không đúng vì chúng chỉ được ghi chú khi cần (chi tiết hơn trong câu hỏi StackOverflow này ).


5
Đó là câu trả lời chính xác cho phiên bản mới nhất của AutoMapper và AspNetCore
Joshit

1
đây là câu trả lời tôi đang tìm kiếm cho AutoMapper 8.1 (phiên bản mới nhất)
Tinaira

30

Câu trả lời của theutz ở đây rất hay, tôi chỉ muốn thêm điều này:

Nếu bạn để hồ sơ ánh xạ kế thừa từ MapperConfigurationExpressionthay vì Profile, bạn có thể chỉ cần thêm một bài kiểm tra để xác minh thiết lập ánh xạ của mình, điều này luôn tiện dụng:

[Fact]
public void MappingProfile_VerifyMappings()
{
    var mappingProfile = new MappingProfile();

    var config = new MapperConfiguration(mappingProfile);
    var mapper = new Mapper(config);

    (mapper as IMapper).ConfigurationProvider.AssertConfigurationIsValid();
}

Tôi nhận được một lỗi: "Tự động phụ thuộc phần mở rộng AutoMapper không tương thích với lõi asp.net 1.1". Xin vui lòng giúp đỡ!
Rohit Arora

Có vẻ như định nghĩa của "xác minh" là tranh luận. Điều này sẽ nổ tung khi một số thuộc tính nhất định được thiết kế để ngăn chặn ánh xạ.
Jeremy Holovacs

2
Nếu bạn không muốn một thuộc tính được ánh xạ, hãy thiết lập nó với .Ignore (). Bằng cách đó, nó buộc bạn phải chủ động suy nghĩ về việc xử lý từng trường hợp - đảm bảo bạn không bỏ lỡ nội dung nào khi thay đổi được thực hiện. Siêu thực tế, thực sự. Vì vậy, có, kiểm tra xác minh là một mạng lưới an toàn lớn hơn nhiều người nhận ra. Nó không phải là hoàn hảo, nhưng nó chăm sóc 90% đầu tiên.
Arve Systad 23/03/18

18

Tôi đã giải quyết nó theo cách này (tương tự như trên nhưng tôi cảm thấy đó là một giải pháp sạch hơn) cho .NET Core 2.2 / Automapper 8.1.1 w / Tiện ích mở rộng.DI 6.1.1.

Tạo lớp MappingProfile.cs và điền vào hàm tạo với Bản đồ (Tôi dự định sử dụng một lớp duy nhất để giữ tất cả ánh xạ của mình)

    public class MappingProfile : Profile
    {
        public MappingProfile()
        {
            CreateMap<Source, Dest>().ReverseMap();
        }
    }

Trong Startup.cs, hãy thêm vào bên dưới để thêm vào DI (đối số lắp ráp dành cho lớp chứa các cấu hình ánh xạ của bạn, trong trường hợp của tôi, đó là lớp MappingProfile).

//add automapper DI
services.AddAutoMapper(typeof(MappingProfile));

Trong Trình điều khiển, sử dụng nó giống như bất kỳ đối tượng DI nào khác

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

        public AnyController(IMapper mapper)
        {
            _mapper = mapper;
        }

        public IActionResult Get(int id)
        {
            var entity = repository.Get(id);
            var dto = _mapper.Map<Dest>(entity);

            return Ok(dto);
        }
    }


2
Tôi thích câu trả lời của bạn. Tôi nghĩ rằng gói MappingProfilesvới new Type[]{}như trong câu trả lời này là không cần thiết.
Người đàn ông quá béo không cổ

10

Trong Startup.cs của tôi (Core 2.2, Automapper 8.1.1)

services.AddAutoMapper(new Type[] { typeof(DAL.MapperProfile) });            

Trong dự án truy cập dữ liệu của tôi

namespace DAL
{
    public class MapperProfile : Profile
    {
        // place holder for AddAutoMapper (to bring in the DAL assembly)
    }
}

Trong định nghĩa mô hình của tôi

namespace DAL.Models
{
    public class PositionProfile : Profile
    {
        public PositionProfile()
        {
            CreateMap<Position, PositionDto_v1>();
        }
    }

    public class Position
    {
        ...
    }

Tại sao bạn không sử dụng services.AddAutoMapper( typeof(DAL.MapperProfile) ); thay vì services.AddAutoMapper(new Type[] { typeof(DAL.MapperProfile) });?
Too Fat Man Không cổ

8

Tôi thích rất nhiều câu trả lời, đặc biệt là câu trả lời của @saineshwar. Tôi đang sử dụng .net Core 3.0 với AutoMapper 9.0, vì vậy tôi cảm thấy đã đến lúc cập nhật câu trả lời của mình.

Điều làm việc cho tôi là trong Startup.ConfigureService (...) đăng ký dịch vụ theo cách này:

    services.AddAutoMapper(cfg => cfg.AddProfile<MappingProfile>(), 
                               AppDomain.CurrentDomain.GetAssemblies());

Tôi nghĩ rằng phần còn lại của câu trả lời @saineshwar giữ cho hoàn hảo. Nhưng nếu có ai quan tâm mã điều khiển của tôi là:

[HttpGet("{id}")]
public async Task<ActionResult> GetIic(int id)
{
    // _context is a DB provider
    var Iic = await _context.Find(id).ConfigureAwait(false);

    if (Iic == null)
    {
        return NotFound();
    }

    var map = _mapper.Map<IicVM>(Iic);

    return Ok(map);
}

Và lớp ánh xạ của tôi:

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Iic, IicVM>()
            .ForMember(dest => dest.DepartmentName, o => o.MapFrom(src => src.Department.Name))
            .ForMember(dest => dest.PortfolioTypeName, o => o.MapFrom(src => src.PortfolioType.Name));
            //.ReverseMap();
    }
}

----- BIÊN TẬP -----

Sau khi đọc các tài liệu được liên kết trong các bình luận của Lucian Bargaoanu, tôi nghĩ tốt hơn nên thay đổi câu trả lời này một chút.

Không tham số services.AddAutoMapper() (có câu trả lời @saineshwar) không hoạt động nữa (ít nhất là đối với tôi). Nhưng nếu bạn sử dụng bộ lắp ráp NuGet AutoMapper.Extensions.Microsoft.DependencyInjection, khung có thể kiểm tra tất cả các lớp mở rộng AutoMapper.Profile (như của tôi, MappingProfile).

Vì vậy, trong trường hợp của tôi, khi lớp thuộc cùng một tổ hợp thực thi, việc đăng ký dịch vụ có thể được rút ngắn thành services.AddAutoMapper(System.Reflection.Assembly.GetExecutingAssembly());
(Một cách tiếp cận thanh lịch hơn có thể là một phần mở rộng không tham số với mã hóa này).

Cảm ơn, Lucian!



6

Tôi đang sử dụng AutoMapper 6.1.1 và asp.net Core 1.1.2.

Trước hết, định nghĩa các lớp Hồ sơ được kế thừa bởi Lớp Hồ sơ của Máy tự động. Tôi đã tạo giao diện IProfile trống, mục đích chỉ là tìm các lớp thuộc loại này.

 public class UserProfile : Profile, IProfile
    {
        public UserProfile()
        {
            CreateMap<User, UserModel>();
            CreateMap<UserModel, User>();
        }
    }

Bây giờ tạo một lớp riêng, ví dụ: Ánh xạ

 public class Mappings
    {
     public static void RegisterMappings()
     {            
       var all =
       Assembly
          .GetEntryAssembly()
          .GetReferencedAssemblies()
          .Select(Assembly.Load)
          .SelectMany(x => x.DefinedTypes)
          .Where(type => typeof(IProfile).GetTypeInfo().IsAssignableFrom(type.AsType()));

            foreach (var ti in all)
            {
                var t = ti.AsType();
                if (t.Equals(typeof(IProfile)))
                {
                    Mapper.Initialize(cfg =>
                    {
                        cfg.AddProfiles(t); // Initialise each Profile classe
                    });
                }
            }         
        }

    }

Bây giờ trong Dự án web MVC Core trong tệp Startup.cs, trong hàm tạo, hãy gọi lớp Ánh xạ sẽ khởi tạo tất cả ánh xạ tại thời điểm tải ứng dụng.

Mappings.RegisterMappings();

Bạn chỉ có thể tạo một lớp con từ lớp hồ sơ và khi chương trình đang chạy services.AddAutoMapper (); dòng mã Trình tự động tự động biết chúng.
isaeid

Tôi không nghĩ rằng điều này là cần thiết nếu bạn sử dụng AutoMapper.Extensions.Microsoft.DependancyInjection có sẵn trong nuget.
Greg Gum

5

Đối với ASP.NET Core (được thử nghiệm bằng 2.0+ và 3.0), nếu bạn muốn đọc tài liệu nguồn: https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection/blob/master/README.md

Mặt khác, làm theo 4 bước sau:

  1. Cài đặt AutoMapper.Extensions.Microsoft.DependancyInjection từ nuget.

  2. Đơn giản chỉ cần thêm một số lớp hồ sơ.

  3. Sau đó thêm bên dưới vào lớp startup.cs của bạn. services.AddAutoMapper(OneOfYourProfileClassNamesHere)

  4. Sau đó, chỉ cần tiêm IMapper trong bộ điều khiển của bạn hoặc bất cứ nơi nào bạn cần:

public class EmployeesController {

    private readonly IMapper _mapper;

    public EmployeesController(IMapper mapper){

        _mapper = mapper;
    }

Và nếu bạn muốn sử dụng ProjectTo thì bây giờ chỉ cần:

var customers = await dbContext.Customers.ProjectTo<CustomerDto>(_mapper.ConfigurationProvider).ToListAsync()

4

Đối với AutoMapper 9.0.0:

public static IEnumerable<Type> GetAutoMapperProfilesFromAllAssemblies()
    {
        foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            foreach (var aType in assembly.GetTypes())
            {
                if (aType.IsClass && !aType.IsAbstract && aType.IsSubclassOf(typeof(Profile)))
                    yield return aType;
            }
        }
    }

MapperProfile:

public class OrganizationProfile : Profile
{
  public OrganizationProfile()
  {
    CreateMap<Foo, FooDto>();
    // Use CreateMap... Etc.. here (Profile methods are the same as configuration methods)
  }
}

Trong khởi nghiệp của bạn:

services.AddAutoMapper(GetAutoMapperProfilesFromAllAssemblies()
            .ToArray());

Trong Bộ điều khiển hoặc dịch vụ: Tiêm mapper:

private readonly IMapper _mapper;

Sử dụng:

var obj = _mapper.Map<TDest>(sourceObject);

4

Tại các phiên bản mới nhất của lõi asp.net, bạn nên sử dụng cách khởi tạo sau:

services.AddAutoMapper(typeof(YourMappingProfileClass));

2

Asp.Net Core 2.2 với AutoMapper.Extensions.Microsoft.DependencyInjection.

public class MappingProfile : Profile
{
  public MappingProfile()
  {
      CreateMap<Domain, DomainDto>();
  }
}

Trong Startup.cs

services.AddAutoMapper(typeof(List.Handler));

1

Để thêm vào những gì Arve Systad đã đề cập để thử nghiệm. Nếu vì bất kỳ lý do gì bạn thích tôi và muốn duy trì cấu trúc thừa kế được cung cấp trong giải pháp theutz, bạn có thể thiết lập MapperConfiguration như vậy:

var mappingProfile = new MappingProfile();
var config = new MapperConfiguration(cfg =>
{
    cfg.AddProfile(mappingProfile);
});
var mapper = new Mapper(config);

Tôi đã làm điều này trong NUnit.


1

dịch vụ.AddAutoMapper (); không làm việc cho tôi. (Tôi đang sử dụng Asp.Net Core 2.0)

Sau khi cấu hình như dưới đây

   var config = new AutoMapper.MapperConfiguration(cfg =>
   {                 
       cfg.CreateMap<ClientCustomer, Models.Customer>();
   });

khởi tạo trình ánh xạ IMapper mapper = config.CreateMapper ();

và thêm đối tượng mapper vào các dịch vụ dưới dạng dịch vụ singleton.AddSingleton (mapper);

bằng cách này tôi có thể thêm DI vào bộ điều khiển

  private IMapper autoMapper = null;

  public VerifyController(IMapper mapper)
  {              
   autoMapper = mapper;  
  }

và tôi đã sử dụng như dưới đây trong các phương pháp hành động của mình

  ClientCustomer customerObj = autoMapper.Map<ClientCustomer>(customer);

Xin chào @venkat có lẽ bạn chỉ cần thêm gói AutoMapper.Extensions.Microsoft.DependancyInjection vào dự án của bạn
dalcam

-1

về câu trả lời của theutz, không cần chỉ định parrameter ánh xạ IMapper tại hàm tạo của bộ điều khiển.

bạn có thể sử dụng Mapper vì nó là thành viên tĩnh tại bất kỳ vị trí nào của mã.

public class UserController : Controller {
   public someMethod()
   {
      Mapper.Map<User, UserDto>(user);
   }
}

11
Nhưng thống kê là một chút chống thử nghiệm, không?
Scott Fraley

3
Vâng. Điều này sẽ hoạt động trong nhiều trường hợp, nhưng nếu bạn không có ánh xạ được cấu hình khi gọi phương thức này trong thử nghiệm, Nó sẽ đưa ra một ngoại lệ (và do đó không thử nghiệm vì lý do sai). Với một mũi tiêm, IMapperbạn có thể chế nhạo nó và, ví dụ, chỉ cần làm cho nó trở về null nếu nó không liên quan đến thử nghiệm đã cho.
Arve Systad
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.