Jestem stosunkowo nowy w .NET i postanowiłem zająć się .NET Core zamiast uczyć się „starych sposobów”. Znalazłem tutaj szczegółowy artykuł na temat konfigurowania AutoMapper dla .NET Core , ale czy dla początkującego jest prostszy przewodnik?
Jestem stosunkowo nowy w .NET i postanowiłem zająć się .NET Core zamiast uczyć się „starych sposobów”. Znalazłem tutaj szczegółowy artykuł na temat konfigurowania AutoMapper dla .NET Core , ale czy dla początkującego jest prostszy przewodnik?
Odpowiedzi:
Rozgryzłem to! Oto szczegóły:
Dodaj pakiet AutoMapper Dependency Injection do swojego rozwiązania za pośrednictwem NuGet .
Utwórz nową klasę dla profilu mapowania. (Utworzyłem klasę w głównym katalogu rozwiązań o nazwie MappingProfile.cs
i dodałem następujący kod.) Jako przykładu użyję obiektu User
i UserDto
.
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>();
}
}
Następnie dodaj AutoMapperConfiguration w Startup.cs
sposób pokazany poniżej:
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();
}
Aby wywołać odwzorowany obiekt w kodzie, wykonaj następujące czynności:
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!
}
}
Mam nadzieję, że to pomoże komuś zacząć od nowa z ASP.NET Core! Czekam na wszelkie uwagi i uwagi, ponieważ wciąż jestem nowy w świecie .NET!
Profile
zlokalizowane są klasy
Krok Aby użyć AutoMapper z ASP.NET Core.
Krok 1. Instalowanie AutoMapper.Extensions.Microsoft.DependencyInjection z pakietu NuGet.
Krok 2. Utwórz folder w rozwiązaniu, aby zachować mapowania o nazwie „Mapowania”.
Krok 3. Po dodaniu folderu Mapping dodaliśmy klasę o nazwie „ MappingProfile ”. Ta nazwa może być czymś wyjątkowym i dobrym do zrozumienia.
W tej klasie zamierzamy zachować wszystkie mapowania.
Krok 4. Inicjowanie programu Mapper przy uruchamianiu „ConfigureServices”
W Startup Class musimy zainicjować utworzony przez nas profil, a także zarejestrować usługę AutoMapper.
Mapper.Initialize(cfg => cfg.AddProfile<MappingProfile>());
services.AddAutoMapper();
Fragment kodu pokazujący metodę ConfigureServices, w której musimy zainicjować i zarejestrować 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);
}}
Krok 5. Uzyskaj wynik.
Aby uzyskać wynik mapowania, musimy zadzwonić do AutoMapper.Mapper.Map i przekazać poprawne miejsce docelowe i źródło.
AutoMapper.Mapper.Map<Destination>(source);
CodeSnippet
[HttpPost]
public void Post([FromBody] SchemeMasterViewModel schemeMaster)
{
if (ModelState.IsValid)
{
var mappedresult = AutoMapper.Mapper.Map<SchemeMaster>(schemeMaster);
}
}
'Mapper' does not contain a definition for 'initialize'
. Używam AutoMapper.Extensions.Microsoft.DependencyInjection
wersji 7.0.0
Chcę rozszerzyć odpowiedzi @ theutz - mianowicie ten wiersz:
// services.AddAutoMapper(typeof(Startup)); // <-- newer automapper version uses this signature.
Jest to błąd ( prawdopodobnie ) w wersji 3.2.0 AutoMapper.Extensions.Microsoft.DependencyInjection. (Używam .NET Core 2.0)
Rozwiązano to w tym problemie GitHub. Jeśli twoje klasy dziedziczące klasy Profile AutoMapper istnieją poza asemblerem, w którym znajduje się klasa startowa, prawdopodobnie nie zostaną zarejestrowane, jeśli twój zastrzyk AutoMapper wygląda następująco:
services.AddAutoMapper();
chyba że wyraźnie określisz, które zespoły mają wyszukiwać profile AutoMapper.
Można to zrobić w następujący sposób w Startup.ConfigureServices:
services.AddAutoMapper(<assembies> or <type_in_assemblies>);
gdzie „ asemblies ” i „type_in_assemblies” wskazują na zespół, w którym określone są klasy Profile w aplikacji. Na przykład:
services.AddAutoMapper(typeof(ProfileInOtherAssembly), typeof(ProfileInYetAnotherAssembly));
Ja przypuszczam (i kładę nacisk na to słowo), które ze względu na realizację następujących przeciążenia bez parametrów (kod źródłowy z GitHub ):
public static IServiceCollection AddAutoMapper(this IServiceCollection services)
{
return services.AddAutoMapper(null, AppDomain.CurrentDomain.GetAssemblies());
}
polegamy na tym, że CLR ma już zestaw JITed zawierający profile AutoMapper, które mogą być lub nie być prawdziwe, ponieważ są one blokowane tylko w razie potrzeby (więcej szczegółów w tym pytaniu StackOverflow).
odpowiedź theutza tutaj jest bardzo dobra, chcę tylko dodać:
Jeśli MapperConfigurationExpression
zamiast tego dziedziczysz profil mapowania Profile
, możesz po prostu dodać test, aby zweryfikować konfigurację mapowania, co zawsze jest przydatne:
[Fact]
public void MappingProfile_VerifyMappings()
{
var mappingProfile = new MappingProfile();
var config = new MapperConfiguration(mappingProfile);
var mapper = new Mapper(config);
(mapper as IMapper).ConfigurationProvider.AssertConfigurationIsValid();
}
Rozwiązałem to w ten sposób (podobnie jak powyżej, ale wydaje mi się, że jest to czystsze rozwiązanie) dla .NET Core 2.2 / Automapper 8.1.1 z rozszerzeniami.DI 6.1.1.
Utwórz klasę MappingProfile.cs i wypełnij konstruktora Mapami (planuję użyć jednej klasy do przechowywania wszystkich moich mapowań)
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<Source, Dest>().ReverseMap();
}
}
W Startup.cs dodaj poniżej, aby dodać do DI (argument zestawu jest dla klasy, która przechowuje twoje konfiguracje mapowania, w moim przypadku jest to klasa MappingProfile).
//add automapper DI
services.AddAutoMapper(typeof(MappingProfile));
W kontrolerze używaj go jak każdego innego obiektu DI
[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);
}
}
MappingProfiles
w new Type[]{}
sposób pokazany w tej odpowiedzi nie jest konieczne.
W moim Startup.cs (Core 2.2, Automapper 8.1.1)
services.AddAutoMapper(new Type[] { typeof(DAL.MapperProfile) });
W moim projekcie dostępu do danych
namespace DAL
{
public class MapperProfile : Profile
{
// place holder for AddAutoMapper (to bring in the DAL assembly)
}
}
W mojej definicji modelu
namespace DAL.Models
{
public class PositionProfile : Profile
{
public PositionProfile()
{
CreateMap<Position, PositionDto_v1>();
}
}
public class Position
{
...
}
services.AddAutoMapper( typeof(DAL.MapperProfile) );
zamiast services.AddAutoMapper(new Type[] { typeof(DAL.MapperProfile) });
?
Lubię wiele odpowiedzi, szczególnie jedną z @saineshwar. Używam .net Core 3.0 z AutoMapper 9.0, więc czuję, że nadszedł czas, aby zaktualizować swoją odpowiedź.
Dla mnie zadziałało Startup.ConfigureServices (...) zarejestruj usługę w ten sposób:
services.AddAutoMapper(cfg => cfg.AddProfile<MappingProfile>(),
AppDomain.CurrentDomain.GetAssemblies());
Myślę, że reszta odpowiedzi @saineshwar pozostaje idealna. Ale jeśli ktoś jest zainteresowany, mój kod kontrolera to:
[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);
}
A moja klasa mapowania:
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();
}
}
----- EDYTOWAĆ -----
Po przeczytaniu dokumentów dołączonych w komentarzach Luciana Bargaoanu, myślę, że lepiej nieco zmienić tę odpowiedź.
Bez parametrów services.AddAutoMapper()
(który miał odpowiedź @saineshwar) już nie działa (przynajmniej dla mnie). Ale jeśli użyjesz zestawu NuGet AutoMapper.Extensions.Microsoft.DependencyInjection, środowisko może sprawdzać wszystkie klasy, które rozszerzają AutoMapper.Profile (takie jak moje, MappingProfile).
Tak więc w moim przypadku, gdy klasa należy do tego samego wykonującego zestawu, rejestracja usługi może zostać skrócona do services.AddAutoMapper(System.Reflection.Assembly.GetExecutingAssembly());
(Bardziej eleganckim podejściem może być bezparametrowe rozszerzenie z tym kodowaniem).
Dzięki, Lucian!
Korzystam z AutoMapper 6.1.1 i asp.net Core 1.1.2.
Przede wszystkim zdefiniuj klasy Profile dziedziczone przez Profile Class of Automapper. Stworzyłem interfejs IProfile, który jest pusty, jego celem jest jedynie znalezienie klas tego typu.
public class UserProfile : Profile, IProfile
{
public UserProfile()
{
CreateMap<User, UserModel>();
CreateMap<UserModel, User>();
}
}
Teraz utwórz oddzielną klasę, np. Mapowania
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
});
}
}
}
}
Teraz w MVC Core web Project w pliku Startup.cs, w konstruktorze, wywołaj klasę Mapping, która zainicjuje wszystkie mapowania podczas ładowania aplikacji.
Mappings.RegisterMappings();
W przypadku programu ASP.NET Core (testowany przy użyciu wersji 2.0+ i 3.0), jeśli wolisz czytać dokumentację źródłową: https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection/blob/master/README.md
W przeciwnym razie następujące 4 kroki działają:
Zainstaluj AutoMapper.Extensions.Microsoft.DependancyInjection z nuget.
Po prostu dodaj kilka klas profili.
Następnie dodaj poniżej swoją klasę startup.cs.
services.AddAutoMapper(OneOfYourProfileClassNamesHere)
Następnie wystarczy wstrzyknąć IMapper do kontrolerów lub tam, gdzie jest to potrzebne:
public class EmployeesController {
private readonly IMapper _mapper;
public EmployeesController(IMapper mapper){
_mapper = mapper;
}
A jeśli chcesz użyć ProjectTo teraz, po prostu:
var customers = await dbContext.Customers.ProjectTo<CustomerDto>(_mapper.ConfigurationProvider).ToListAsync()
W przypadku 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)
}
}
W twoim startupie:
services.AddAutoMapper(GetAutoMapperProfilesFromAllAssemblies()
.ToArray());
W kontrolerze lub usłudze: Inject mapper:
private readonly IMapper _mapper;
Stosowanie:
var obj = _mapper.Map<TDest>(sourceObject);
Aby dodać do tego, co Arve Systad wspomniał o testowaniu. Jeśli z jakiegokolwiek powodu jesteś podobny do mnie i chcesz zachować strukturę dziedziczenia podaną w rozwiązaniu theutz, możesz skonfigurować MapperConfiguration w następujący sposób:
var mappingProfile = new MappingProfile();
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile(mappingProfile);
});
var mapper = new Mapper(config);
Zrobiłem to w NUnit.
services.AddAutoMapper (); nie działało dla mnie. (Używam Asp.Net Core 2.0)
Po skonfigurowaniu jak poniżej
var config = new AutoMapper.MapperConfiguration(cfg =>
{
cfg.CreateMap<ClientCustomer, Models.Customer>();
});
zainicjuj program mapujący IMapper mapper = config.CreateMapper ();
i dodaj obiekt mapujący do usług jako usługi singleton.AddSingleton (mapper);
w ten sposób mogę dodać DI do kontrolera
private IMapper autoMapper = null;
public VerifyController(IMapper mapper)
{
autoMapper = mapper;
}
i użyłem jak poniżej w moich metodach działania
ClientCustomer customerObj = autoMapper.Map<ClientCustomer>(customer);
Jeśli chodzi o odpowiedź theutz, nie ma potrzeby określania parametru konwertera IMapper w konstruktorze kontrolerów.
możesz użyć Mapera, ponieważ jest on statycznym elementem w dowolnym miejscu kodu.
public class UserController : Controller {
public someMethod()
{
Mapper.Map<User, UserDto>(user);
}
}
IMapper
możesz wyśmiewać to i, na przykład, po prostu ustawić wartość zero, jeśli nie ma to znaczenia dla danego testu.