0
votes

I was developing a blog project based on asp.net core mvc and trying to deploy my project on ubuntu 16.04 LTS x86-64.

And I encountered a null reference exception while using transactionScope with dapper on inserting object to sql server.

The SQL server version is: 12.0.4100.1 running on a Windows 2012SP1 system. and the code was running just fine on Windows 10 (OS Build 17074.1002). but when I deploy the project to Ubuntu, it throws null reference exceptions.

the exception details was like:

{System.NullReferenceException: Object reference not set to an instance of an object. at System.Data.ProviderBase.DbConnectionPool.DeactivateObject(DbConnectionInternal obj) at System.Data.ProviderBase.DbConnectionPool.PutObject(DbConnectionInternal obj, Object owningObject) at System.Data.ProviderBase.DbConnectionInternal.CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory) at System.Data.SqlClient.SqlConnection.CloseInnerConnection() at System.Data.SqlClient.SqlConnection.Close() at Dapper.SqlMapper.d__64 1.MoveNext() in C:\projects\dapper\Dapper\SqlMapper.Async.cs:line 1191 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at System.Runtime.CompilerServices.TaskAwaiter 1.GetResult() at Autyan.NiChiJou.Repository.Dapper.BaseDapperRepository 1.d__22.MoveNext() in /home/alex/Documents/Github/Autyan.NiChiJou/src/Autyan.NiChiJou.Repository.Dapper/BaseDapperRepository.cs:line 167 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at System.Runtime.CompilerServices.TaskAwaiter 1.GetResult() at Autyan.NiChiJou.Repository.Dapper.LongKeyDapperRepository 1.d__1.MoveNext() in /home/alex/Documents/Github/Autyan.NiChiJou/src/Autyan.NiChiJou.Repository.Dapper/LongKeyDapperRepository.cs:line 23 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at System.Runtime.CompilerServices.TaskAwaiter 1.GetResult() at Autyan.NiChiJou.Service.Blog.ArticleService.d__10.MoveNext() in /home/alex/Documents/Github/Autyan.NiChiJou/src/Autyan.NiChiJou.Service.Blog/ArticleService.cs:line 39}

my code that throws exception is like this:

using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
    var create = await ArticleRepo.InsertAsync(article);
    if (create <= 0)
    {
        return Failed<Article>("create article failed");
    }
    create = await ContentRepo.InsertAsync(new ArticleContent
    {
        ArticleId = create,
        Content = content
    });
    if (create <= 0)
    {
        return Failed<Article>("create articleContent failed");
    }
    scope.Complete();
}

I tried to remove the transactionScope and after that, my codes run just fine with everything

the new code was like:

var create = await ArticleRepo.InsertAsync(article);
if (create <= 0)
{
    return Failed<Article>("create article failed");
}
create = await ContentRepo.InsertAsync(new ArticleContent
{
    ArticleId = create,
    Content = content
});
if (create <= 0)
{
    return Failed<Article>("create articleContent failed");
}

Am I using trancsationScope the wrong way? Or it's just a bug from dotnet core itself?

1

1 Answers

0
votes

It is because when await is over, thread assigned to continue execution of statements following await already lost the transaction context that original executing thread had.

Define your Txn Scope as :

using (var scope = new TransactionScope(..., TransactionScopeAsyncFlowOption.Enabled))