I'm writting web application in ASP.NET Web API and working on method to modify restaurant informations. The core entity is Restaurant that looks like this:
public class Restaurant
{
public int Id { get; set; }
public string Name { get; set; }
public string? Description { get; set; }
public string Category { get; set; }
public bool HasDelivery { get; set; }
public string ContactEmail { get; set; }
public string ContactNumber { get; set; }
public int? CreatedById { get; set; }
public virtual User CreatedBy { get; set; }
public int AddressId { get; set; }
public virtual Address Address { get; set; }
public virtual List<Dish> Dishes { get; set; }
}
What is the most important in here - the HasDelivery
property must be not-nullable. It has to take one of true or false value.
Next, I have ModifyRestaurantDto class which is given as a request from body while the app working. Just like the following:
public class ModifyRestaurantDto
{
[MaxLength(25)]
public string? Name { get; set; }
[MaxLength(100)]
public string? Description { get; set; }
public bool? HasDelivery { get; set; }
}
To simplify I've just given a few of properties that are allowed to be changed. Note that all of them are nullable types. I also have a service method called UpdateAsync, as follows:
public async Task UpdateAsync(int id, ModifyRestaurantDto modifyRestaurantDto)
{
var restaurant = await _dbContext
.Restaurants
.FirstOrDefaultAsync(r => r.Id == id)
?? throw new NotFoundException("Restaurant not found...");
var authorizationResult = _authorizationService
.AuthorizeAsync(
_userContextService.User,
restaurant,
new ResourceOperationRequirement(ResourceOperation.Update))
.Result;
if (!authorizationResult.Succeeded)
throw new ForbidException();
_mapper.Map(modifyRestaurantDto, restaurant);
await _dbContext.SaveChangesAsync();
}
What I want to achieve is to change only values which has been given in request body (in ModifyRestaurantDto). E.g. if my json body was looking like this
{
"name": "Foo"
}
I wouldn't want Description and HasDelivery props to change. Now, I've created AutoMapper profile and configured it inside Program.cs of course.
public class RestaurantMappingProfile : Profile
{
public RestaurantMappingProfile()
{
CreateMap<ModifyRestaurantDto, Restaurant>()
.ForAllMembers(opts => opts.Condition((src, dest, value) => value is not null));
}
}
And while given types are string
everything works correctly. The problem is that nullable bool is always converted to false anyways. I'm using .NET 6.0 and have enabled Nullable and ImplicitUsings in .csproj.
Do you have some idea why only nullable booleans are not overlooked by AutoMapper?
CodePudding user response:
It seems like a bug to me. A quick fix would be adding mapping from bool?
to bool
:
CreateMap<bool?, bool>().ConvertUsing((src, dest) => src ?? dest);
CreateMap<ModifyRestaurantDto, Restaurant>()
.ForAllMembers(opts => opts.Condition((_, _, v) => v is not null));