Я создаю трехуровневый веб-API ASP.NET Core. Он состоит из слоев Data, Business (Core) и WebAPI:
- Основной уровень независим (не знает ни EFCore, ни какого-либо другого проекта)
- Уровень данных - имеет ссылку на Coreи EFCore
- Уровень WebAPI - последний уровень, знает о ядре, данных и EFCore
Я пытался принять решение, как обрабатывать транзакции БД. Я внедряю DbContext (scoped) в мои Data
классы, а также в Controller (я опускаю бизнес-проект, так как он вообще не знает EFCore). Поскольку существует только один экземпляр DbContext
на запрос, это тот же объект в Data
, как и в контроллере.
Итак, бизнес-логика выполняет то, что должно делать, вызываяобъекты в слое данных. Всякий раз, когда слою данных требуется сохранить изменения в БД, он делает это. Все обернуто вокруг транзакции по запросу. Так что, если что-то пойдет не так ... все изменения будут отменены.
Это метод примера контроллера, который показывает, как я это сделал (упрощенно):
[HttpPut("{id}")]
public IActionResult UpdateMeeting(int id, [FromBody] MeetingDto meeting)
{
using (var transaction = _dbContext.Database.BeginTransaction())
{
if (meeting == null)
{
return BadRequest();
}
_meetingService.AddMeetingChanges(meeting);
meeting.Id = id;
_meetingService.UpdateMeeting(meeting);
}
return NoContent();
}
Все прекрасно работает. Так в чем же проблема? Мне нужно повторить это:
using (var transaction = _dbContext.Database.BeginTransaction())
{
}
... в каждой операции, которая требует транзакции.
Итак, я подумал, возможно ли запустить транзакцию в промежуточном программном обеспечении / конвейере (Я не уверен в терминологии). Проще говоря - я хочу начать транзакцию явно для КАЖДОГО запроса. Я хочу спрятаться в промежуточном программном обеспечении. Так что всякий раз, когда я внедряю DbContext в классы данных, транзакция уже начинается
РЕДАКТИРОВАТЬ: возможное решение:
Создано UnitOfWork
класс:
public class UnitOfWork
{
private readonly RequestDelegate _next;
public UnitOfWork(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext, MyContext ctx)
{
using (var transaction = ctx.Database.BeginTransaction())
{
await _next(httpContext);
transaction.Commit();
}
}
}
Введено UnitOfWork
класс в качестве промежуточного программного обеспечения после UseHttpsRedirection
и до UseMvc
:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(appBuilder =>
{
appBuilder.Run(async context =>
{
context.Response.StatusCode = 500;
await context.Response.WriteAsync("An unexpected error happened. Please contact IT.");
});
});
}
app.UseHttpsRedirection();
app.UseMiddleware<UnitOfWork>();
app.UseMvc();
}