Starts in:
1 DAY
19 HRS
18 MIN
56 SEC
Starts in:
1 D
19 H
18 M
56 S
Open Closed

Unit of work not performing rollback on exception in appservice #939


User avatar
0
pontus created

Check the docs before asking a question: https://docs.abp.io/en/commercial/latest/ Check the samples, to see the basic tasks: https://docs.abp.io/en/commercial/latest/samples/index The exact solution to your question may have been answered before, please use the search on the homepage.

  • ABP Framework version: v4.2.1
  • UI type: Angular
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): yes
  • Exception message and stack trace:
  • Steps to reproduce the issue: Created brand new solution with the abp cli. Created a book entity and a db set. Created the migration and and added an app service.

(The BookStoreAppService inherits from AppService).

When i try this from swagger i get the 500 response as expected, however the book is still saved to the database.

Is there something obvoius that I'm missing? Somehow it seems to serious to have been overlooked :)


9 Answer(s)
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    I can't reproduce your problem.

    Can you provide a project to reproduce? thanks.

  • User Avatar
    0
    pontus created

    https://github.com/PontusLjungdahl/abpbook2

  • User Avatar
    0
    Moyaoxiang created

    Hi pontus, You only need to delete the app.UseUnitOfWork(); statement in BookStoreHttpApiHostModule. the reason: ABP will use AbpUowActionFilter to process work units by default. After adding middleware, it will use AbpUnitOfWorkMiddleware to create work units first. In AbpUowActionFilter, the original Exception was swallowed, and AbpUnitOfWorkMiddleware considered that no exception occurred, so the data was submitted to the database. I think this is a bug.

  • User Avatar
    0
    pontus created

    Thank you.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    https://github.com/PontusLjungdahl/abpbook2

    Please remove the repo on Github, because the source code has your linence key, it's not safe for you.

  • User Avatar
    0
    pontus created

    Hi,

    https://github.com/PontusLjungdahl/abpbook2

    Please remove the repo on Github, because the source code has your linence key, it's not safe for you.

    Thank you, it's removed.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    https://github.com/abpframework/abp/pull/7804

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    HI,

    We will fix it by https://github.com/abpframework/abp/pull/7804

    For now , you can try:

    public class MyAbpUowActionFilter : IAsyncActionFilter, ITransientDependency
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            if (!context.ActionDescriptor.IsControllerAction())
            {
                await next();
                return;
            }
    
            var methodInfo = context.ActionDescriptor.GetMethodInfo();
            var unitOfWorkAttr = UnitOfWorkHelper.GetUnitOfWorkAttributeOrNull(methodInfo);
    
            context.HttpContext.Items["_AbpActionInfo"] = new AbpActionInfoInHttpContext
            {
                IsObjectResult = context.ActionDescriptor.HasObjectResult()
            };
    
            if (unitOfWorkAttr?.IsDisabled == true)
            {
                await next();
                return;
            }
    
            var options = CreateOptions(context, unitOfWorkAttr);
    
            var unitOfWorkManager = context.HttpContext.RequestServices.GetRequiredService<IUnitOfWorkManager>();
    
            //Trying to begin a reserved UOW by AbpUnitOfWorkMiddleware
            if (unitOfWorkManager.TryBeginReserved(UnitOfWork.UnitOfWorkReservationName, options))
            {
                var result = await next();
                if (!Succeed(result))
                {
                    await RollbackAsync(context, unitOfWorkManager);
                }
    
                return;
            }
    
            //Begin a new, independent unit of work
            using (var uow = unitOfWorkManager.Begin(options))
            {
                var result = await next();
                if (Succeed(result))
                {
                    await uow.CompleteAsync(context.HttpContext.RequestAborted);
                }
                else
                {
                    await uow.RollbackAsync(context.HttpContext.RequestAborted);
                }
            }
        }
    
        private AbpUnitOfWorkOptions CreateOptions(ActionExecutingContext context,
            UnitOfWorkAttribute unitOfWorkAttribute)
        {
            var options = new AbpUnitOfWorkOptions();
    
            unitOfWorkAttribute?.SetOptions(options);
    
            if (unitOfWorkAttribute?.IsTransactional == null)
            {
                var abpUnitOfWorkDefaultOptions =
                    context.HttpContext.RequestServices.GetRequiredService<IOptions<AbpUnitOfWorkDefaultOptions>>().Value;
                options.IsTransactional = abpUnitOfWorkDefaultOptions.CalculateIsTransactional(
                    autoValue: !string.Equals(context.HttpContext.Request.Method, HttpMethod.Get.Method,
                        StringComparison.OrdinalIgnoreCase)
                );
            }
    
            return options;
        }
    
        private async Task RollbackAsync(ActionExecutingContext context, IUnitOfWorkManager unitOfWorkManager)
        {
            var currentUow = unitOfWorkManager.Current;
            if (currentUow != null)
            {
                await currentUow.RollbackAsync(context.HttpContext.RequestAborted);
            }
        }
    
        private static bool Succeed(ActionExecutedContext result)
        {
            return result.Exception == null || result.ExceptionHandled;
        }
    }
    
    Configure<MvcOptions>(options =>
    {
        options.Filters.RemoveAll(x => x.GetType() == typeof(AbpUowActionFilter));
        options.Filters.Add<MyAbpUowActionFilter>();
    });
    

    AbpUowPageFilter also.

  • User Avatar
    0
    ServiceBot created
    Support Team Automatic process manager

    This question has been automatically marked as stale because it has not had recent activity.

Made with ❤️ on ABP v9.1.0-preview. Updated on November 20, 2024, 13:06