Мне тоже нужно было иметь AsyncController
, который я легко изменил FilterResolvingActionInvoker
, чтобы он основывался на AsyncControllerActionInvoker
вместо ControllerActionInvoker
.
Но возникли другие проблемы из-за автоматического удаления транзакции после завершения запроса. В AsyncController
начальный поток и поток, который завершает запрос, могут отличаться, что вызывает следующее исключение в методе Dispose класса TransactionManager
:
A TransactionScope
должен располагаться в том же потоке, в котором он был создан.
Это исключение подавляется без какой-либо регистрации, и его действительно было трудно обнаружить. В этом случае сеанс остается нераспределенным, и последующие сеансы будут остановлены.
Поэтому я сделал метод dispose открытым для 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
.