Rainbow.Dapper.Database.Dispose(true) should never throw an exception
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 18.4k
- Forks
- 3.7k
- Avg merge
- 5h 8m
- Merged PRs (30d)
- 1
Description
The current implementation of this method is the following:
public void Dispose()
{
if (_connection.State != ConnectionState.Closed)
{
_transaction?.Rollback();
_connection.Close();
_connection = null;
}
}
Here's one problem. If this method is called in "using" statement or as a part of an explicit "finally" block it may happen so that it will fail and throw and exception of its own, thus, hiding the original exception.
Here's one case i'm getting from time to time:
System.InvalidOperationException: This SqlTransaction has completed; it is no longer usable.
at System.Data.SqlClient.SqlTransaction.ZombieCheck()
at System.Data.SqlClient.SqlTransaction.Rollback()
at Dapper.Database`1.Dispose() in C:\projects\dapper\Dapper.Rainbow\Database.cs:line 473
at MyClass.MyMethod() in D:\MyClass.cs:line 666
Here, as we can see the original exception is lost forever. The only work-around I can invent is to do it like this (pseudo-code):
using (db = NewDb())
{
try
{
db.BeginTransaction();
// Useful work
db.CommitTransaction();
}
catch (ex)
{
Log(ex);
throw;
}
}
which kind of sucks, especially taking into account that we need to put this boiler plate in every place we use Rainbow.Database.
Actually, it's a good practice to not throw from Dispose(true).
Thoughts?
I can provide a PR if it's going to be accepted.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in Dapper.Rainbow/Database.cs at Database.Dispose(), using the reported SqlTransaction.Rollback stack trace as the entry point. Review how disposal interacts with completed transactions and connection closing. Done means disposing after a transaction failure or completion does not throw its own exception or hide the caller's original exception.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, sql
- Domain
- backend, database
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100