-1

A bit of context on how I'm using TransactionScope, as of currently in the program if any of the three databases' queries catches an error, I made it so that the TransactionScope will dispose everything which results in none of the data getting passed. This part of the program is working fine.

Another bit of context being that the framework I'm using is ASP.NET Boilerplate.

Included below will be the codes minus some details due to confidentiality.

public CUDResult TriTransaction(TransactItem[] item)
{
    CUDResult result = new CUDResult();
    using (TransactionScope ts = new TransactionScope())
    {
        try
        {
            result = InsertItem(item);
            if (result.success == false)
                return result;
            ts.Complete();
        }
        catch (Exception)
        {
            ts.Dispose();
            return result;
        }
    }
    return result;
}

The concern right now is the fact that the framework I'm using will see the dispose as a server error and will always return the fixed error message for said server error An internal error occurred during your request.

Though the back-end works the way I want it to, I'd prefer if dispose doesn't get caught as a server error and causing the front-end to display the aforementioned error message.

Included below will be the error message logged.

ERROR 2021-04-26 14:34:04,260 [::1] [Chrome90] [20] Abp.WebApi.ExceptionHandling.AbpApiExceptionFilterAttribute - The transaction has aborted.
System.Transactions.TransactionAbortedException: The transaction has aborted.
   at System.Transactions.TransactionStateAborted.BeginCommit(InternalTransaction tx, Boolean asyncCommit, AsyncCallback asyncCallback, Object asyncState)
   at System.Transactions.CommittableTransaction.Commit()
   at System.Transactions.TransactionScope.InternalDispose()
   at System.Transactions.TransactionScope.Dispose()
   at Abp.EntityFramework.Uow.TransactionScopeEfTransactionStrategy.Commit()
   at Abp.EntityFramework.Uow.EfUnitOfWork.CompleteUow()
   at Abp.Domain.Uow.UnitOfWorkBase.Complete()
   at Abp.Domain.Uow.UnitOfWorkInterceptor.PerformSyncUow(IInvocation invocation, UnitOfWorkOptions options)
   at Abp.Domain.Uow.UnitOfWorkInterceptor.PerformUow(IInvocation invocation, UnitOfWorkOptions options)
   at Abp.Domain.Uow.UnitOfWorkInterceptor.Intercept(IInvocation invocation)
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Abp.Auditing.AuditingInterceptor.PerformSyncAuditing(IInvocation invocation, AuditInfo auditInfo)
   at Abp.Auditing.AuditingInterceptor.Intercept(IInvocation invocation)
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Abp.Runtime.Validation.Interception.ValidationInterceptor.Intercept(IInvocation invocation)
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.XXXAppServiceProxy.TriTransaction(TransactItem[] item)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Abp.WebApi.Controllers.Dynamic.Interceptors.AbpDynamicApiControllerInterceptor`1.Intercept(IInvocation invocation)
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.DynamicApiController`1Proxy_4.TriTransaction(TransactItem[] item)
   at lambda_method(Closure , Object , Object[] )
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass6_2.<GetExecutor>b__2(Object instance, Object[] methodParameters)
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__17`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__17`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Abp.WebApi.Uow.AbpApiUowFilter.<ExecuteActionFilterAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__17`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Abp.WebApi.Validation.AbpApiValidationFilter.<ExecuteActionFilterAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__17`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Abp.WebApi.Auditing.AbpApiAuditFilter.<ExecuteActionFilterAsync>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__17`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Abp.WebApi.Security.AntiForgery.AbpAntiForgeryApiFilter.<ExecuteAuthorizationFilterAsync>d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__17`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Abp.WebApi.Authorization.AbpApiAuthorizeFilter.<ExecuteAuthorizationFilterAsync>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__17`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.AuthenticationFilterResult.<ExecuteAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__6.MoveNext()

I suspect that it might not just be the fact that dispose is being caught as an error and it might be something else entirely but I do not have enough knowledge regarding this and would like to know if there are any way to solve the issue with the front-end always showing An internal error occurred during your request error message whenever the transaction is intentionally disposed.

  • Does this only happen when `InsertItem(item)` throws an error? – MindSwipe Apr 26 '21 at 08:24
  • At any point in InsertItem(item) that it catches an error, result.success will be set to false and will return the result, effectively calling ts.dispose based on what I understand on how TransactionScope works. So in a way, yes it only happens when InsertItem(item) throws an error. – Pporing Dysrexn Apr 26 '21 at 08:39
  • I need to re phrase my question: Does this happen only when an exception thrown inside `InsertItem(item)` bubbles up to your `catch (Exception)` inside the using block? – MindSwipe Apr 26 '21 at 08:45
  • It happens whenever `dispose` is called. I've tried manually setting the ts.dispose to be at the start in case the issue was because I misunderstood how the `using` works but it still shows the same issue as previously mentioned. – Pporing Dysrexn Apr 26 '21 at 09:00
  • 1
    Then your problem is probably that you're calling dispose twice. The `using` statement is really just syntactic sugar for `TransactionScope ts = new TransactionScope; try { ... } finally { ts.Dispose() }`. Check out [this](https://sharplab.io/#v2:EYLgZgpghgLgrgJwgZwLQEsB2MIIA4D2ANrBACarIwJYDmqAxgZlVNsgDRkgDUAPgAEATAEYAsAChJmKAFsUeKAwgACAKIAPOXiIRJAb0krjK4aZEB2IycMST900KHWHK2648CADCoAUANygEFTAVAF4VTAgAdxUAMQICXwBKZJcPY3cMk3SMgF9ckwK7IvT0swSCFRAVAEkAEXRkQmQoYF10rNcBAGZTABYVRuaCZAgUwszJlWni+2K8oA=) to see how it's implemented in code – MindSwipe Apr 26 '21 at 09:07
  • 1
    You are disposing twice because you have a `using` block. Just remove the line `ts.Dispose();` it os unnecessary – Charlieface Apr 26 '21 at 09:08

1 Answers1

1

Your problem is that your calling Dispose twice, you should never need to call Dispose manually, that's what the using statement is for. using (...) is basically just some syntactic sugar for a try/ finally block. So this:

using (var foo = new Foo())
{
    foo.SayHello();
}

Gets compiled as

Foo foo = new Foo();
try
{
    foo.SayHello();
}
finally
{
    if (foo != null)
    {
        ((IDisposable)foo).Dispose();
    }
}

Meaning your code gets compiled as

CUDResult result = new CUDResult();
TransactionScope ts = new TransactionScope();
try
{
    try
    {
        result = InsertItem(item);
        if (!result.success) // instead of result.success == false
            return result;
        ts.Complete();
    }
    catch (Exception)
    {
        ts.Dispose();
        return result;
    }
}
finally
{
    if (ts != null)
    {
        ((IDisposable)ts).Dispose();
    }
}

return result;

Which makes it obvious, that when an exception is caught, you're disposing ts twice

MindSwipe
  • 7,193
  • 24
  • 47
  • I've removed the `dispose` but the error still shows up in the front-end. I appreciate the explanation but I don't believe the issue causing the error in the front-end is because of the `ts` getting disposed twice. – Pporing Dysrexn Apr 27 '21 at 01:00