-
Notifications
You must be signed in to change notification settings - Fork 0
v1.0.15 #34
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
v1.0.15 #34
Conversation
Release v1.0
Release v1.0
Release v1.0
Release v1.0
Release v1.0
Release v1.0
Release v1.0
…overloads-for-ensure-and-ensureasync-methods 32 add lazy error evaluation overloads for ensure and ensureasync methods
Reviewer's GuideExtends the Result extensions with lazily-evaluated Ensure/EnsureAsync overloads and introduces IServiceScopeFactory helpers to execute work in new DI scopes with optional Unit of Work handling and ambient service provider propagation. Sequence diagram for ExecuteInNewUnitOfWorkScopeAsync extensionsequenceDiagram
actor Caller
participant ScopeFactory as IServiceScopeFactory
participant Scope as IAsyncServiceScope
participant Ambient as AmbientServiceProvider
participant SP as IServiceProvider
participant UowManager as IUnitOfWorkManager
participant Uow as IUnitOfWork
Caller->>ScopeFactory: ExecuteInNewUnitOfWorkScopeAsync(action, options, cancellationToken)
ScopeFactory->>ScopeFactory: CreateAsyncScope()
ScopeFactory-->>Scope: IAsyncServiceScope
Scope->>SP: get ServiceProvider
SP-->>Caller: IServiceProvider (sp)
Caller->>Ambient: set Current = sp
SP->>UowManager: GetRequiredService<IUnitOfWorkManager>()
UowManager-->>Caller: IUnitOfWorkManager
Caller->>UowManager: BeginAsync(options, cancellationToken)
UowManager-->>Uow: IUnitOfWork
Caller->>Caller: await action(sp)
Caller->>Uow: CommitAsync(cancellationToken)
Caller->>Scope: DisposeAsync()
Caller->>Uow: DisposeAsync()
Caller->>Ambient: restore previous Current
Caller-->>Caller: task completes
Class diagram for new lazy Ensure overloads in ResultExtensionsclassDiagram
class Result~T~ {
bool IsSuccess
T Value
static Result~T~ Fail(Error error)
}
class Error {
}
class ResultExtensions {
<<static>>
+Result~T~ Ensure~T~(Result~T~ result, Func~T,bool~ predicate, Error error)
+Result~T~ Ensure~T~(Result~T~ result, Func~T,bool~ predicate, Func Error errorFactory)
+Result~T~ Ensure~T~(Result~T~ result, Func~T,bool~ predicate, Func~T,Error~ errorFactory)
+Task~Result~T~~ EnsureAsync~T~(Result~T~ result, Func~T,Task~bool~~ predicate, Error error)
+Task~Result~T~~ EnsureAsync~T~(Result~T~ result, Func~T,Task~bool~~ predicate, Func Error errorFactory)
+Task~Result~T~~ EnsureAsync~T~(Result~T~ result, Func~T,Task~bool~~ predicate, Func~T,Error~ errorFactory)
+Task~Result~T~~ EnsureAsync~T~(Task~Result~T~~ task, Func~T,bool~ predicate, Error error)
+Task~Result~T~~ EnsureAsync~T~(Task~Result~T~~ task, Func~T,bool~ predicate, Func Error errorFactory)
+Task~Result~T~~ EnsureAsync~T~(Task~Result~T~~ task, Func~T,bool~ predicate, Func~T,Error~ errorFactory)
}
ResultExtensions ..> Result : uses
ResultExtensions ..> Error : creates
Class diagram for new ServiceScopeFactoryExtensions and related typesclassDiagram
class IServiceScopeFactory {
+IAsyncServiceScope CreateAsyncScope()
}
class IAsyncServiceScope {
+IServiceProvider ServiceProvider
+ValueTask DisposeAsync()
}
class IServiceProvider {
+T GetService~T~()
}
class IUnitOfWorkManager {
+Task~IUnitOfWork~ BeginAsync(UnitOfWorkOptions options, CancellationToken cancellationToken)
}
class IUnitOfWork {
+Task CommitAsync(CancellationToken cancellationToken)
+ValueTask DisposeAsync()
}
class UnitOfWorkOptions {
}
class AmbientServiceProvider {
<<static>>
+IServiceProvider Current
}
class ServiceScopeFactoryExtensions {
<<static>>
+Task ExecuteInNewUnitOfWorkScopeAsync(IServiceScopeFactory scopeFactory, Func~IServiceProvider,Task~ action, UnitOfWorkOptions options, CancellationToken cancellationToken)
+Task~T~ ExecuteInNewUnitOfWorkScopeAsync~T~(IServiceScopeFactory scopeFactory, Func~IServiceProvider,Task~T~~ func, UnitOfWorkOptions options, CancellationToken cancellationToken)
+Task ExecuteInNewScopeAsync(IServiceScopeFactory scopeFactory, Func~IServiceProvider,Task~ action)
+Task~T~ ExecuteInNewScopeAsync~T~(IServiceScopeFactory scopeFactory, Func~IServiceProvider,Task~T~~ func)
}
ServiceScopeFactoryExtensions ..> IServiceScopeFactory : extends
ServiceScopeFactoryExtensions ..> IAsyncServiceScope : creates
ServiceScopeFactoryExtensions ..> IServiceProvider : uses
ServiceScopeFactoryExtensions ..> IUnitOfWorkManager : resolves
ServiceScopeFactoryExtensions ..> IUnitOfWork : manages
ServiceScopeFactoryExtensions ..> UnitOfWorkOptions : configures
ServiceScopeFactoryExtensions ..> AmbientServiceProvider : sets Current
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Caution Review failedThe pull request is closed. Note
|
| Cohort / File(s) | Summary |
|---|---|
Dependency Injection Scope Execution framework/src/BBT.Aether.Core/BBT/Aether/DependencyInjection/ServiceScopeFactoryExtensions.cs |
New extension class with 4 methods: ExecuteInNewUnitOfWorkScopeAsync (with/without generic return) manages scope creation, ambient provider propagation, Unit of Work lifecycle (begin/commit), and context restoration; ExecuteInNewScopeAsync (with/without generic return) provides same pattern without UoW management. All methods handle cancellation and ensure proper disposal. |
Result Validation Enhancement framework/src/BBT.Aether.Core/BBT/Aether/Results/ResultExtensions.cs |
Adds 6 new Ensure overloads: 2 sync variants on Result<T> with lazy error factories (accepting either no arguments or the value); 4 async variants on Result<T> and Task<Result<T>> with same error factory patterns. All implement predicate-based validation with lazy error creation, preserving successful results and producing failed states on predicate failure. |
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 minutes
Suggested reviewers
- ukaratas
Poem
🐰 Hops of joy through scopes so new,
With UnitOfWork and results true,
Ambient whispers flow from place to place,
Error factories craft responses with grace,
Extensions blooming—let code run free!
✨ Finishing touches
- 📝 Generate docstrings
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Post copyable unit tests in a comment
- Commit unit tests in branch
master
📜 Recent review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
framework/src/BBT.Aether.Core/BBT/Aether/DependencyInjection/ServiceScopeFactoryExtensions.csframework/src/BBT.Aether.Core/BBT/Aether/Results/ResultExtensions.cs
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
Summary of ChangesHello @yilmaztayfun, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request enhances the framework by providing robust mechanisms for managing dependency injection scopes and Unit of Work patterns through new Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey - I've found 1 issue, and left some high level feedback:
- In ServiceScopeFactoryExtensions, there is an extra closing brace at the end of the file, which results in three closing braces instead of the expected two (class and namespace); this will prevent the file from compiling and should be removed.
- The four ExecuteIn*ScopeAsync methods duplicate the same ambient service provider scoping pattern; consider extracting the common ambient context handling into a shared helper to reduce duplication and the risk of inconsistencies on future changes.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In ServiceScopeFactoryExtensions, there is an extra closing brace at the end of the file, which results in three closing braces instead of the expected two (class and namespace); this will prevent the file from compiling and should be removed.
- The four ExecuteIn*ScopeAsync methods duplicate the same ambient service provider scoping pattern; consider extracting the common ambient context handling into a shared helper to reduce duplication and the risk of inconsistencies on future changes.
## Individual Comments
### Comment 1
<location> `framework/src/BBT.Aether.Core/BBT/Aether/DependencyInjection/ServiceScopeFactoryExtensions.cs:48` </location>
<code_context>
+
+ // Commit UnitOfWork
+ await uow.CommitAsync(cancellationToken);
+ }
+ finally
+ {
</code_context>
<issue_to_address>
**issue (bug_risk):** There is an extra closing brace at the end of the file which will cause a compile error.
The class and namespace are already closed, so the final `}` leaves the file with unbalanced braces. Remove that last brace at the end of the file.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
|
||
| // Commit UnitOfWork | ||
| await uow.CommitAsync(cancellationToken); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (bug_risk): There is an extra closing brace at the end of the file which will cause a compile error.
The class and namespace are already closed, so the final } leaves the file with unbalanced braces. Remove that last brace at the end of the file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces valuable additions to the framework. The new Ensure and EnsureAsync overloads with lazy error evaluation for the Result type are a great performance enhancement. The ServiceScopeFactoryExtensions also provide useful helpers for managing dependency injection scopes and units of work. My review includes a couple of suggestions to refactor the new service scope extensions to reduce code duplication, which will improve long-term maintainability. Overall, the changes are well-implemented and beneficial.
| public static async Task ExecuteInNewUnitOfWorkScopeAsync( | ||
| this IServiceScopeFactory scopeFactory, | ||
| Func<IServiceProvider, Task> action, | ||
| UnitOfWorkOptions? options = null, | ||
| CancellationToken cancellationToken = default) | ||
| { | ||
| await using var scope = scopeFactory.CreateAsyncScope(); | ||
| var sp = scope.ServiceProvider; | ||
|
|
||
| // Propagate ambient service provider for the new scope | ||
| var previousAmbient = AmbientServiceProvider.Current; | ||
| AmbientServiceProvider.Current = sp; | ||
|
|
||
| try | ||
| { | ||
| var uowManager = sp.GetRequiredService<IUnitOfWorkManager>(); | ||
|
|
||
| // Begin UnitOfWork | ||
| await using var uow = await uowManager.BeginAsync(options, cancellationToken); | ||
|
|
||
| // Execute action | ||
| await action(sp); | ||
|
|
||
| // Commit UnitOfWork | ||
| await uow.CommitAsync(cancellationToken); | ||
| } | ||
| finally | ||
| { | ||
| // Restore previous ambient context | ||
| AmbientServiceProvider.Current = previousAmbient; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method duplicates the logic for creating a scope and managing the AmbientServiceProvider, which is already handled by ExecuteInNewScopeAsync. To improve maintainability and reduce code duplication, you can refactor this method to delegate the scope management to ExecuteInNewScopeAsync and wrap the unit of work logic within it.
public static Task ExecuteInNewUnitOfWorkScopeAsync(
this IServiceScopeFactory scopeFactory,
Func<IServiceProvider, Task> action,
UnitOfWorkOptions? options = null,
CancellationToken cancellationToken = default)
{
return scopeFactory.ExecuteInNewScopeAsync(async sp =>
{
var uowManager = sp.GetRequiredService<IUnitOfWorkManager>();
// Begin UnitOfWork
await using var uow = await uowManager.BeginAsync(options, cancellationToken);
// Execute action
await action(sp);
// Commit UnitOfWork
await uow.CommitAsync(cancellationToken);
});
}| public static async Task<T> ExecuteInNewUnitOfWorkScopeAsync<T>( | ||
| this IServiceScopeFactory scopeFactory, | ||
| Func<IServiceProvider, Task<T>> func, | ||
| UnitOfWorkOptions? options = null, | ||
| CancellationToken cancellationToken = default) | ||
| { | ||
| await using var scope = scopeFactory.CreateAsyncScope(); | ||
| var sp = scope.ServiceProvider; | ||
|
|
||
| // Propagate ambient service provider for the new scope | ||
| var previousAmbient = AmbientServiceProvider.Current; | ||
| AmbientServiceProvider.Current = sp; | ||
|
|
||
| try | ||
| { | ||
| var uowManager = sp.GetRequiredService<IUnitOfWorkManager>(); | ||
|
|
||
| // Begin UnitOfWork | ||
| await using var uow = await uowManager.BeginAsync(options, cancellationToken); | ||
|
|
||
| // Execute function | ||
| var result = await func(sp); | ||
|
|
||
| // Commit UnitOfWork | ||
| await uow.CommitAsync(cancellationToken); | ||
|
|
||
| return result; | ||
| } | ||
| finally | ||
| { | ||
| // Restore previous ambient context | ||
| AmbientServiceProvider.Current = previousAmbient; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the non-generic version, this method duplicates the scope creation and AmbientServiceProvider management logic from ExecuteInNewScopeAsync<T>. Refactoring to use ExecuteInNewScopeAsync<T> will make the code more concise and easier to maintain by avoiding redundant code.
public static Task<T> ExecuteInNewUnitOfWorkScopeAsync<T>(
this IServiceScopeFactory scopeFactory,
Func<IServiceProvider, Task<T>> func,
UnitOfWorkOptions? options = null,
CancellationToken cancellationToken = default)
{
return scopeFactory.ExecuteInNewScopeAsync(async sp =>
{
var uowManager = sp.GetRequiredService<IUnitOfWorkManager>();
// Begin UnitOfWork
await using var uow = await uowManager.BeginAsync(options, cancellationToken);
// Execute function
var result = await func(sp);
// Commit UnitOfWork
await uow.CommitAsync(cancellationToken);
return result;
});
}
|



Summary by Sourcery
Add lazy-evaluated error support to Result Ensure helpers and introduce DI scope utilities for running work in isolated scopes and units of work.
New Features:
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.