I'm looking for good explanation of https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-web-api?view=aspnetcore-6.0&tabs=visual-studio
My case is PUT endpoint. I need to update entity in database with optimistic locking. I don't want to expose all properties to user. Only some of them are valid but not all. For example I don't want user to modify date of update.
- Should I put it in BeginTrasaction/Commit block?
- Is my code good enough?
- Why do I need variable in route when I have dto in body?
class MyEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long? Id {get; set;}
public string P1 {get; set;}
public string P2 {get; set;}
public DateTime? UpdatedAt {get; set;}
public Guid ConcurrencyStamp {get; set;} = Guid.NewGuid();
}
[HttpPut]
[Route("{id}")]
public async Task<IActionResult> Update([FromRoute]long? id, [FromBody]SomeUpdateDTO model)
{
if (id != model.Id)
return BadRequest();
try
{
if (!await dbContext.MyEntities.Where(e => e.Id == id).AnyAsync())
return NotFound();
else
{
var entity = new MyEntity()
{
Id = id,
P1 = model.P1,
P2 = model.P2,
UpdatedAt = DateTime.UtcNow,
... and some properties that cannot be updated by external DTO like UpdatedAt
ConcurrencyStamp = Guid.NewGuid(),
};
dbContext.Attach(entity);
dbContext.Entry(entity).Property(e => e.P1).IsModified = true;
dbContext.Entry(entity).Property(e => e.P2).IsModified = true;
dbContext.Entry(entity).Property(e => e.UpdatedAt).IsModified = true;
dbContext.Entry(entity).Property(e => e.ConcurrencyStamp).IsModified = true;
dbContext.Entry(entity).Property(e => e.ConcurrencyStamp).OriginalValue = model.ConcurrencyStamp;
await dbContext.SaveChangesAsync();
return base.NoContent();
}
}
catch (DbUpdateConcurrencyException) when (!dbContext.MyEntities.Any(e => e.Id == id))
{
return NotFound();
}
catch (DbUpdateConcurrencyException ex)
{
return Conflict();
}