Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IInterceptor not refreshing inject #46

Open
RtypeStudios opened this issue Mar 8, 2018 · 0 comments
Open

IInterceptor not refreshing inject #46

RtypeStudios opened this issue Mar 8, 2018 · 0 comments
Assignees

Comments

@RtypeStudios
Copy link

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?

@scott-xu scott-xu self-assigned this Mar 8, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants