I am working on a new ASP.NET Core 3.1.1 API with Microsoft.AspNetCore.OData v 7.3.0, AutoMapper v9.0.0 and Microsoft.AspNetCore.Mvc.NewtonsoftJson v3.1.1
I am getting the following error when I make a POST to the Accounts endpoint using Postman v7.18.0;
AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping.
I have reviewed the similar questions list when creating this question but was unable to find a solution. In reviewing google searches for AutoMapper OData Enums all I could find were the recommendation to decorate my dto class with...
[AutoMap(typeof(Account))]
... and to decorate my dto enum properties with ...
[JsonConverter(typeof(StringEnumConverter))]
However, I still get the error. I found references to using an AutoMapperProfile class with a mapper defined as
CreateMap<Account, AccountModel>().ReverseMap();
But it appears that AutoMapper v9.0.0 no longer has a CreateMap method. My understanding was that adding the [AutoMap(typeof(Account))] to the dto class had the same effect as creating the map in the profile class.
I feel like I am going in circles at this point here so I though I would reach out to the SO community. I am sure it is something simple, I am just not seeing it.
Here is my POST request body from Postman;
{
"@odata.context": "https://localhost:44367/v1/$metadata#Accounts",
"AccountName": "Test Provider",
"AccountType": "Provider",
"IsTaxExempt": false,
"Status": "Active"
}
Here is my AccountsController Post method;
[ODataRoute]
[Produces("application/json;odata.metadata=minimal")]
[ProducesResponseType(typeof(AccountModel), Status201Created)]
[ProducesResponseType(Status400BadRequest)]
public async Task<IActionResult> Post([FromBody] AccountModel record)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
record.Id = new Guid();
var entity = _mapper.Map<Account>(record);
_context.Add(entity);
await _context.SaveChangesAsync();
var createdRecord = _mapper.Map<AccountModel>(entity);
return Created(createdRecord);
}
Here is my Account entity class;
public class Account : EntityBase
{
[Required]
[Column(TypeName = "nvarchar(50)")]
[MaxLength(50)]
public string AccountName { get; set; }
public AccountTypes AccountType { get; set; }
public bool IsTaxExempt { get; set; }
}
Here is the EntityBase class;
public class EntityBase
{
[Required]
public Guid Id { get; set; }
public DateTimeOffset? DateTimeCreated { get; set; } = DateTime.UtcNow;
public DateTimeOffset? DateTimeLastModified { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public StatusTypes Status { get; set; }
public bool DeleteFlag { get; set; }
}
Here is my Account DTO class;
[Filter, Count, Expand, OrderBy, Page, Select]
[AutoMap(typeof(Account))]
public class AccountModel : BaseModel
{
[Required]
[MaxLength(50)]
public string AccountName { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public AccountTypes AccountType { get; set; }
public bool IsTaxExempt { get; set; }
}
Here is my BaseModel class;
[Select, Filter]
public class BaseModel
{
public Guid Id { get; set; }
public DateTimeOffset DateTimeCreated { get; set; } = DateTime.UtcNow;
public DateTimeOffset DateTimeLastModified { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public StatusTypes Status { get; set; }
public bool DeleteFlag { get; set; }
}
And here are my Enums for AccountTypes and StatusTypes
public enum AccountTypes
{
Customer = 0,
Reseller = 1,
Provider = 2,
}
public enum StatusTypes
{
Active = 0,
Inactive = 1,
}
Any ideas?
It turns out that I needed to create an instance of an AutoMapper MapperConfiguration and assign it to the mapper.
I ended up putting in in the constructor of the Controller, for example;
public AccountsController(CdContext context, IMapper mapper)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
var config = new MapperConfiguration(cfg => cfg.CreateMap<Account, AccountModel>().ReverseMap());
_mapper = new Mapper(config);
}
After I did this, everything worked as expected.
Here is a link to AutoMappers docs on the subject.