I have a simple command as per the CQRS pattern as follows:
public sealed class EditPersonalInfoCommandHandler : ICommandHandler<EditPersonalInfoCommand> {
private readonly AppDbContext _context;
public EditPersonalInfoCommandHandler(AppDbContext context) {
_context = context;
}
public Result Handle(EditPersonalInfoCommand command) {
var studentRepo = new StudentRepository(_context);
Student student = studentRepo.GetById(command.Id);
if (student == null) {
return Result.Failure($"No Student found for Id {command.Id}");
}
student.Name = command.Name;
student.Email = command.Email;
_context.SaveChanges();
return Result.Success();
}
}
Now I have a requirement to attempt _context.SaveChanges()
upto 5 times if it fails with an exception. For this I can simply have a for loop in the method as:
for(int i = 0; i < 5; i++) {
try {
//required logic
} catch(SomeDatabaseException e) {
if(i == 4) {
throw;
}
}
}
The requirement is to execute the method as a single unit. The thing is that once the _context.SaveChanges()
throws an exception, the same _context
cannot be used to reattempt the logic. The docs say:
Discard the current DbContext. Create a new DbContext and restore the state of your application from the database. Inform the user that the last operation might not have been completed successfully.
However, in the Startup.cs
, I have the AppDbContext
as a scoped dependency. In order to reattempt the method logic I require a new instance of AppDbContext
but being registered as scoped will not allow that.
One solution that comes to my mind is to make the AppDbContext
transient. But I have a feeling that by doing that I will open whole set of new problems for myself. Can anyone help me with it?