の代わりに基づいてAsyncController
簡単に変更できるものが必要でした。FilterResolvingActionInvoker
AsyncControllerActionInvoker
ControllerActionInvoker
しかし、リクエストの完了後に自動的にトランザクションが破棄されるため、別の問題がありました。AsyncController
開始スレッドとリクエストを完了するスレッドは異なる場合があり、クラスの Dispose メソッドで次の例外をスローしますTransactionManager
。
ATransactionScope
は、それが作成されたのと同じスレッドで破棄する必要があります。
この例外はログなしで抑制されており、実際に見つけるのは困難でした。この場合、セッションは破棄されないままになり、後続のセッションはタイムアウトになります。
だから私は、データベースへのクエリが必要なときはいつでもITransactionManager
、私AsyncController
はそれをラップします:
using (_services.TransactionManager) {
.....
}
新しい TransactionManager :
public interface ITransactionManager : IDependency, IDisposable {
void Demand();
void Cancel();
}
public class TransactionManager : ITransactionManager {
private TransactionScope _scope;
private bool _cancelled;
public TransactionManager() {
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
public void Demand() {
if (_scope == null) {
Logger.Debug("Creating transaction on Demand");
_scope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions {
IsolationLevel = IsolationLevel.ReadCommitted
});
_cancelled = false;
}
}
void ITransactionManager.Cancel() {
Logger.Debug("Transaction cancelled flag set");
_cancelled = true;
}
void IDisposable.Dispose() {
if (_scope != null) {
if (!_cancelled) {
Logger.Debug("Marking transaction as complete");
_scope.Complete();
}
Logger.Debug("Final work for transaction being performed");
try {
_scope.Dispose();
}
catch {
// swallowing the exception
}
Logger.Debug("Transaction disposed");
}
_scope = null;
}
}
に他の小さな変更を加えたことに注意してくださいTransactionManager
。