-
Notifications
You must be signed in to change notification settings - Fork 27
Open
Description
Hi There,
We recently updated to the latest Ninject and Ninject extensions library. We have noticed we are now getting disposed exceptions when using the following generic transaction interceptor.
It appears even though we are running the below in request scope it is still holding onto a previous instance of the EF context and using it to try and start a new transaction. Where previously we were getting a new context instance for each request scope.
/// <summary>
/// Used to mark a method that requires being wrapped in a transaction.
/// </summary>
public class UseTransactionAttribute : InterceptAttribute
{
private readonly IsolationLevel _isolationLevel;
/// <summary>
/// Initializes a new instance of the <see cref="UseTransactionAttribute"/> class.
/// </summary>
public UseTransactionAttribute(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
{
_isolationLevel = isolationLevel;
}
/// <summary>
/// Create the interceptor attached to this attribute.
/// </summary>
/// <param name="request">The proxy request being made.</param>
/// <returns>A <see cref="IInterceptor"/> to wrap the method in.</returns>
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
var isolationLevel = new ConstructorArgument("isolationLevel", _isolationLevel);
return request.Kernel.Get<UseTransactionInterceptor>(isolationLevel);
}
}
/// <summary>
/// Transaction method is responsible for wrapping a method in a transaction in a consistent way.
/// </summary>
public class UseTransactionInterceptor : IInterceptor
{
private readonly IObjectContextAdapter _context;
private readonly IsolationLevel _isolationLevel;
/// <summary>
/// Initializes a new instance of the <see cref="UseTransactionInterceptor"/> class.
/// </summary>
public UseTransactionInterceptor(IObjectContextAdapter context, IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
{
_context = context;
_isolationLevel = isolationLevel;
}
/// <summary>
/// Intercept the method call so it can be wrapped in a transaction. Check if a transaction is active, if it isn't start a new one otherwise do nothing as we are already in one.
/// </summary>
/// <param name="invocation">The invocation we are wrapping a transaction around.</param>
public void Intercept(IInvocation invocation)
{
var database = ((DbContext)_context).Database;
// Don't start another transaction if we are already in one.
if (database.CurrentTransaction != null)
{
invocation.Proceed();
}
else
{
using (var transaction = database.BeginTransaction(_isolationLevel))
{
try
{
invocation.Proceed();
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
}
}
If we replace the line
var database = ((DbContext)_context).Database;
with:
var t = invocation.Request.Kernel.Get<IObjectContextAdapter>();
var database = ((DbContext)t).Database;
We get the behavior we were getting before. So it appears the interceptor is being cached perhaps? Or is this an expected behavior change?
Metadata
Metadata
Assignees
Labels
No labels