ASP.NET Core Web API - Как скрыть транзакцию DbContext в конвейере промежуточного программного обеспечения? - PullRequest
1 голос
/ 03 октября 2019

Я создаю трехуровневый веб-API ASP.NET Core. Он состоит из слоев Data, Business (Core) и WebAPI:

  1. Основной уровень независим (не знает ни EFCore, ни какого-либо другого проекта)
  2. Уровень данных - имеет ссылку на Coreи EFCore
  3. Уровень 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 в классы данных, транзакция уже начинается

РЕДАКТИРОВАТЬ: возможное решение:

  1. Создано 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();
            }
        }
    }   
    
  2. Введено 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();
    }
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...