Ejemplo n.º 1
0
        // This primary overload is specified on the interface itself
        //public static Task<TResult> ExecuteInDbContextScopeAsync<TDbContext, TState, TResult>(this IDbContextProvider<TDbContext> provider,
        //	AmbientScopeOption scopeOption,
        //	TState state, CancellationToken cancellationToken, Func<IExecutionScope<TState>, CancellationToken, Task<TResult>> task)
        //{
        //	return provider.ExecuteInDbContextScopeAsync(scopeOption, state, cancellationToken, task);
        //}

        /// <summary>
        /// <para>
        /// Performs the given <paramref name="task"/>, with access to a new ambient <typeparamref name="TDbContext"/> accessible through <see cref="IDbContextAccessor{TDbContext}"/>.
        /// </para>
        /// <para>
        /// This is the preferred way to perform work in the scope of a <see cref="DbContext"/>. It takes care of many concerns automatically.
        /// </para>
        /// <para>
        /// The task is performed through the <see cref="DbContext"/>'s <see cref="IExecutionStrategy"/>.
        /// The <see cref="IExecutionStrategy"/> may provide behavior such as retry attempts on transient exceptions.
        /// Each attempt is provided with a fresh <see cref="DbContext"/>, with no state leakage.
        /// </para>
        /// <para>
        /// If a query is executed that might perform a write operation, a transaction is started automatically.
        /// (This comes at no additional cost, since otherwise Entity Framework starts its own transaction when saving.)
        /// The transaction is committed once the scope ends, provided that it has not aborted.
        /// </para>
        /// <para>
        /// Scopes can be nested. When a scope joins an outer scope, its work is simply performed as part of the outer scope's work, with the outer scope taking care of all the above.
        /// </para>
        /// <para>
        /// A scope aborts when an exception bubbles up from its task or when <see cref="IExecutionScope.Abort"/> is called. At the end of an aborted scope, any ongoing transaction is rolled back.
        /// Further attempts to use that <see cref="DbContext"/>, even by joined parent scopes, result in a <see cref="TransactionAbortedException"/>.
        /// </para>
        /// </summary>
        internal static Task ExecuteInDbContextScopeAsync <TDbContext, TState>(this IDbContextProvider <TDbContext> provider,
                                                                               AmbientScopeOption scopeOption,
                                                                               TState state, CancellationToken cancellationToken, Func <IExecutionScope <TState>, CancellationToken, Task> task)
        {
            return(provider.ExecuteInDbContextScopeAsync(scopeOption, state, cancellationToken, ExecuteAndReturnTrue));

            // Local function that executes the given task and returns true
            async Task <bool> ExecuteAndReturnTrue(IExecutionScope <TState> executionScope, CancellationToken cancellationToken)
            {
                await task(executionScope, cancellationToken).ConfigureAwait(false);

                return(true);
            }
        }
Ejemplo n.º 2
0
 /// <summary>
 /// <para>
 /// Performs the given <paramref name="task"/>, with access to a new ambient <typeparamref name="TDbContext"/> accessible through <see cref="IDbContextAccessor{TDbContext}"/>.
 /// </para>
 /// <para>
 /// This is the preferred way to perform work in the scope of a <see cref="DbContext"/>. It takes care of many concerns automatically.
 /// </para>
 /// <para>
 /// The task is performed through the <see cref="DbContext"/>'s <see cref="IExecutionStrategy"/>.
 /// The <see cref="IExecutionStrategy"/> may provide behavior such as retry attempts on transient exceptions.
 /// Each attempt is provided with a fresh <see cref="DbContext"/>, with no state leakage.
 /// </para>
 /// <para>
 /// If a query is executed that might perform a write operation, a transaction is started automatically.
 /// (This comes at no additional cost, since otherwise Entity Framework starts its own transaction when saving.)
 /// The transaction is committed once the scope ends, provided that it has not aborted.
 /// </para>
 /// <para>
 /// Scopes can be nested. When a scope joins an outer scope, its work is simply performed as part of the outer scope's work, with the outer scope taking care of all the above.
 /// </para>
 /// <para>
 /// A scope aborts when an exception bubbles up from its task or when <see cref="IExecutionScope.Abort"/> is called. At the end of an aborted scope, any ongoing transaction is rolled back.
 /// Further attempts to use that <see cref="DbContext"/>, even by joined parent scopes, result in a <see cref="TransactionAbortedException"/>.
 /// </para>
 /// </summary>
 public static Task <TResult> ExecuteInDbContextScopeAsync <TDbContext, TState, TResult>(this IDbContextProvider <TDbContext> provider,
                                                                                         TState state, CancellationToken cancellationToken, Func <IExecutionScope <TState>, CancellationToken, Task <TResult> > task)
 {
     return(provider.ExecuteInDbContextScopeAsync(provider.Options.DefaultScopeOption, state, cancellationToken, task));
 }
Ejemplo n.º 3
0
 /// <summary>
 /// <para>
 /// Performs the given <paramref name="task"/>, with access to a new ambient <typeparamref name="TDbContext"/> accessible through <see cref="IDbContextAccessor{TDbContext}"/>.
 /// </para>
 /// <para>
 /// This is the preferred way to perform work in the scope of a <see cref="DbContext"/>. It takes care of many concerns automatically.
 /// </para>
 /// <para>
 /// The task is performed through the <see cref="DbContext"/>'s <see cref="IExecutionStrategy"/>.
 /// The <see cref="IExecutionStrategy"/> may provide behavior such as retry attempts on transient exceptions.
 /// Each attempt is provided with a fresh <see cref="DbContext"/>, with no state leakage.
 /// </para>
 /// <para>
 /// If a query is executed that might perform a write operation, a transaction is started automatically.
 /// (This comes at no additional cost, since otherwise Entity Framework starts its own transaction when saving.)
 /// The transaction is committed once the scope ends, provided that it has not aborted.
 /// </para>
 /// <para>
 /// Scopes can be nested. When a scope joins an outer scope, its work is simply performed as part of the outer scope's work, with the outer scope taking care of all the above.
 /// </para>
 /// <para>
 /// A scope aborts when an exception bubbles up from its task or when <see cref="IExecutionScope.Abort"/> is called. At the end of an aborted scope, any ongoing transaction is rolled back.
 /// Further attempts to use that <see cref="DbContext"/>, even by joined parent scopes, result in a <see cref="TransactionAbortedException"/>.
 /// </para>
 /// </summary>
 public static Task <TResult> ExecuteInDbContextScopeAsync <TDbContext, TResult>(this IDbContextProvider <TDbContext> provider,
                                                                                 AmbientScopeOption scopeOption,
                                                                                 Func <IExecutionScope, Task <TResult> > task)
 {
     return(provider.ExecuteInDbContextScopeAsync(scopeOption, state: task, default, (scope, _) => scope.State(scope)));
Ejemplo n.º 4
0
 /// <summary>
 /// <para>
 /// Performs the given <paramref name="task"/>, with access to a new ambient <typeparamref name="TDbContext"/> accessible through <see cref="IDbContextAccessor{TDbContext}"/>.
 /// </para>
 /// <para>
 /// This is the preferred way to perform work in the scope of a <see cref="DbContext"/>. It takes care of many concerns automatically.
 /// </para>
 /// <para>
 /// The task is performed through the <see cref="DbContext"/>'s <see cref="IExecutionStrategy"/>.
 /// The <see cref="IExecutionStrategy"/> may provide behavior such as retry attempts on transient exceptions.
 /// Each attempt is provided with a fresh <see cref="DbContext"/>, with no state leakage.
 /// </para>
 /// <para>
 /// If a query is executed that might perform a write operation, a transaction is started automatically.
 /// (This comes at no additional cost, since otherwise Entity Framework starts its own transaction when saving.)
 /// The transaction is committed once the scope ends, provided that it has not aborted.
 /// </para>
 /// <para>
 /// Scopes can be nested. When a scope joins an outer scope, its work is simply performed as part of the outer scope's work, with the outer scope taking care of all the above.
 /// </para>
 /// <para>
 /// A scope aborts when an exception bubbles up from its task or when <see cref="IExecutionScope.Abort"/> is called. At the end of an aborted scope, any ongoing transaction is rolled back.
 /// Further attempts to use that <see cref="DbContext"/>, even by joined parent scopes, result in a <see cref="TransactionAbortedException"/>.
 /// </para>
 /// </summary>
 public static Task ExecuteInDbContextScopeAsync <TDbContext>(this IDbContextProvider <TDbContext> provider,
                                                              CancellationToken cancellationToken, Func <IExecutionScope, CancellationToken, Task> task)
 {
     return(provider.ExecuteInDbContextScopeAsync(provider.Options.DefaultScopeOption, state: task, cancellationToken, (scope, ct) => scope.State(scope, ct)));
 }
Ejemplo n.º 5
0
 /// <summary>
 /// <para>
 /// Performs the given <paramref name="task"/>, with access to a new ambient <typeparamref name="TDbContext"/> accessible through <see cref="IDbContextAccessor{TDbContext}"/>.
 /// </para>
 /// <para>
 /// This is the preferred way to perform work in the scope of a <see cref="DbContext"/>. It takes care of many concerns automatically.
 /// </para>
 /// <para>
 /// The task is performed through the <see cref="DbContext"/>'s <see cref="IExecutionStrategy"/>.
 /// The <see cref="IExecutionStrategy"/> may provide behavior such as retry attempts on transient exceptions.
 /// Each attempt is provided with a fresh <see cref="DbContext"/>, with no state leakage.
 /// </para>
 /// <para>
 /// If a query is executed that might perform a write operation, a transaction is started automatically.
 /// (This comes at no additional cost, since otherwise Entity Framework starts its own transaction when saving.)
 /// The transaction is committed once the scope ends, provided that it has not aborted.
 /// </para>
 /// <para>
 /// Scopes can be nested. When a scope joins an outer scope, its work is simply performed as part of the outer scope's work, with the outer scope taking care of all the above.
 /// </para>
 /// <para>
 /// A scope aborts when an exception bubbles up from its task or when <see cref="IExecutionScope.Abort"/> is called. At the end of an aborted scope, any ongoing transaction is rolled back.
 /// Further attempts to use that <see cref="DbContext"/>, even by joined parent scopes, result in a <see cref="TransactionAbortedException"/>.
 /// </para>
 /// </summary>
 public static Task <TResult> ExecuteInDbContextScopeAsync <TDbContext, TResult>(this IDbContextProvider <TDbContext> provider,
                                                                                 AmbientScopeOption scopeOption,
                                                                                 CancellationToken cancellationToken, Func <IExecutionScope, CancellationToken, Task <TResult> > task)
 {
     return(provider.ExecuteInDbContextScopeAsync(scopeOption, state: task, cancellationToken, (scope, ct) => scope.State(scope, ct)));
 }
        /// <summary>
        /// Executes the requested overload of <see cref="IDbContextProvider{TDbContext}.ExecuteInDbContextScope{TState, TResult}"/> or its async variant.
        /// </summary>
        private protected async Task <TResult> Execute <TResult>(Overload overload, IDbContextProvider <TestDbContext> provider, Func <IExecutionScope, CancellationToken, Task <TResult> > task,
                                                                 AmbientScopeOption scopeOption      = AmbientScopeOption.JoinExisting,
                                                                 CancellationToken cancellationToken = default)
        {
            switch (overload)
            {
            case Overload.Async:
                await provider.ExecuteInDbContextScopeAsync(WithoutResultWithoutCancellation(task));

                return(default);

            case Overload.AsyncResult:
                return(await provider.ExecuteInDbContextScopeAsync(WithoutCancellation(task)));

            case Overload.Sync:
                provider.ExecuteInDbContextScope(SyncWithoutResult(task));
                return(default);

            case Overload.SyncResult:
                return(provider.ExecuteInDbContextScope(Sync(task)));

            case Overload.AsyncWithScopeOption:
                await provider.ExecuteInDbContextScopeAsync(scopeOption, WithoutResultWithoutCancellation(task));

                return(default);

            case Overload.AsyncResultWithScopeOption:
                return(await provider.ExecuteInDbContextScopeAsync(scopeOption, WithoutCancellation(task)));

            case Overload.SyncWithScopeOption:
                provider.ExecuteInDbContextScope(scopeOption, SyncWithoutResult(task));
                return(default);

            case Overload.SyncResultWithScopeOption:
                return(provider.ExecuteInDbContextScope(scopeOption, Sync(task)));

            case Overload.AsyncWithCancellation:
                await provider.ExecuteInDbContextScopeAsync(cancellationToken, WithoutResult(task));

                return(default);

            case Overload.AsyncResultWithCancellation:
                return(await provider.ExecuteInDbContextScopeAsync(cancellationToken, task));

            case Overload.AsyncWithScopeOptionWithCancellation:
                await provider.ExecuteInDbContextScopeAsync(scopeOption, cancellationToken, WithoutResult(task));

                return(default);

            case Overload.AsyncResultWithScopeOptionWithCancellation:
                return(await provider.ExecuteInDbContextScopeAsync(scopeOption, cancellationToken, task));

            case Overload.AsyncWithState:
                await provider.ExecuteInDbContextScopeAsync(true, cancellationToken, WithoutResult(task));

                return(default);

            case Overload.AsyncResultWithState:
                return(await provider.ExecuteInDbContextScopeAsync(true, cancellationToken, task));

            case Overload.SyncWithState:
                provider.ExecuteInDbContextScope(true, SyncWithoutResult(task));
                return(default);

            case Overload.SyncResultWithState:
                return(provider.ExecuteInDbContextScope(true, Sync(task)));

            case Overload.AsyncWithScopeOptionWithState:
                await provider.ExecuteInDbContextScopeAsync(scopeOption, true, cancellationToken, WithoutResult(task));

                return(default);

            case Overload.AsyncResultWithScopeOptionWithState:
                return(await provider.ExecuteInDbContextScopeAsync(scopeOption, true, cancellationToken, task));

            case Overload.SyncWithScopeOptionWithState:
                provider.ExecuteInDbContextScope(scopeOption, true, SyncWithoutResult(task));
                return(default);

            case Overload.SyncResultWithScopeOptionWithState:
                return(provider.ExecuteInDbContextScope(scopeOption, true, Sync(task)));

            default:
                throw new NotImplementedException();
            }
        }