Search code examples
c#rollbackaspnetboilerplateunit-of-worktransactionscope

Throw exception to rollback and redirect to another action at the same time


I am attempting to redirect an action to another one when an exception occurs. In addition, I want to rollback all changes at the same time. Rollbacking data is done by throwing an exception but when we throw an exception, the redirect is not working. (I use a framework (ABP) that handles rollback automatically when an exception is thrown, so there is no "BeginTransaction" and "Commit" etc. in my code.)

When the code runs, it just rollback changes to data and show exception but not redirect.

[HttpPost]
public async Task<ActionResult> action1()
{
    var exception=false;

    try
    {
        await method1();

        return RedirectToAction("Success", "Result");
    }
    catch (Exception e)
    {
        exception = true;
        return RedirectToAction("ShowError", "Result");
    }
    finally
    {
        if (exception == true)
            throw new Exception("1000"); 
    }
}

public async Task<ActionResult> method1()
{
    // Some changes on database
}

Solution

  • ABP's Conventional Unit of Work is scoped around your Controller action action1.

    You should require a new unit of work that is scoped within your try block:

    [HttpPost]
    public async Task<ActionResult> action1()
    {
        try
        {
            using (var uow = _unitOfWorkManager.Begin(TransactionScopeOption.RequiresNew))
            {
                await method1();
                uow.Complete();
            }
    
            return RedirectToAction("Success", "Result");
        }
        catch (Exception e)
        {
            return RedirectToAction("ShowError", "Result");
        }
    }
    

    Alternatively, you can make method1 virtual and mark it with the UnitOfWork attribute:

    [HttpPost]
    public async Task<ActionResult> action1()
    {
        try
        {
            await method1();
    
            return RedirectToAction("Success", "Result");
        }
        catch (Exception e)
        {
            return RedirectToAction("ShowError", "Result");
        }
    }
    
    [UnitOfWork(TransactionScopeOption.RequiresNew)]
    public virtual async Task<ActionResult> method1()
    {
        // Some changes on database
    }
    

    Reference: How to return -1 in catch block (aspnetboilerplate/aspnetboilerplate#2732)