diff --git a/source/AliaSQL.Core/AliaSQL.Core.csproj b/source/AliaSQL.Core/AliaSQL.Core.csproj index 62b59d8..5b20688 100644 --- a/source/AliaSQL.Core/AliaSQL.Core.csproj +++ b/source/AliaSQL.Core/AliaSQL.Core.csproj @@ -58,6 +58,7 @@ + @@ -69,7 +70,10 @@ + + + diff --git a/source/AliaSQL.Core/Services/IApplicationSettings.cs b/source/AliaSQL.Core/Services/IApplicationSettings.cs new file mode 100644 index 0000000..1c3763e --- /dev/null +++ b/source/AliaSQL.Core/Services/IApplicationSettings.cs @@ -0,0 +1,9 @@ +using System; + +namespace AliaSQL.Core.Services +{ + internal interface IApplicationSettings + { + TimeSpan? Timeout(); + } +} \ No newline at end of file diff --git a/source/AliaSQL.Core/Services/Impl/ApplicationSettings.cs b/source/AliaSQL.Core/Services/Impl/ApplicationSettings.cs new file mode 100644 index 0000000..bcf1271 --- /dev/null +++ b/source/AliaSQL.Core/Services/Impl/ApplicationSettings.cs @@ -0,0 +1,25 @@ +using System; +using System.Configuration; + +namespace AliaSQL.Core.Services.Impl +{ + internal class ApplicationSettings : IApplicationSettings + { + public TimeSpan? Timeout() + { + var timeoutValue = ConfigurationManager.AppSettings["aliasql.transaction.timeout"]; + + if (string.IsNullOrEmpty(timeoutValue)) + { + return null; + } + + if (!TimeSpan.TryParse(timeoutValue, out var time)) + { + return null; + } + + return time; + } + } +} diff --git a/source/AliaSQL.Core/Services/Impl/QueryExecutor.cs b/source/AliaSQL.Core/Services/Impl/QueryExecutor.cs index f03a9cb..b7e84c2 100644 --- a/source/AliaSQL.Core/Services/Impl/QueryExecutor.cs +++ b/source/AliaSQL.Core/Services/Impl/QueryExecutor.cs @@ -72,7 +72,7 @@ public void ExecuteNonQuery(ConnectionSettings settings, string sql, bool includ public void ExecuteNonQueryTransactional(ConnectionSettings settings, string sql) { //do all this in a single transaction - using (var scope = new TransactionScope()) + using (var scope = new TransactionProvider().CreateTransactionScope()) { string connectionString = _connectionStringGenerator.GetConnectionString(settings, true); using (var connection = new SqlConnection(connectionString)) diff --git a/source/AliaSQL.Core/Services/Impl/TransactionProvider.cs b/source/AliaSQL.Core/Services/Impl/TransactionProvider.cs new file mode 100644 index 0000000..b851cb4 --- /dev/null +++ b/source/AliaSQL.Core/Services/Impl/TransactionProvider.cs @@ -0,0 +1,34 @@ +using System.Reflection; +using System.Transactions; + +namespace AliaSQL.Core.Services.Impl +{ + internal class TransactionProvider + { + private readonly IApplicationSettings _applicationSettings; + + public TransactionProvider() + { + _applicationSettings = new ApplicationSettings(); + } + + private void SetTransactionManagerField(string fieldName, object value) + { + typeof(TransactionManager).GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Static)?.SetValue(null, value); + } + + public TransactionScope CreateTransactionScope() + { + var timeout = _applicationSettings.Timeout(); + + if (timeout == null) + { + return new TransactionScope(); + } + + SetTransactionManagerField("_cachedMaxTimeout", true); + SetTransactionManagerField("_maximumTimeout", timeout.GetValueOrDefault()); + return new TransactionScope(TransactionScopeOption.RequiresNew, timeout.GetValueOrDefault()); + } + } +}