Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/AppHost/AppHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
var redis = builder.AddRedis("redis");

builder.AddProject<Projects.Web>("web")
.WithReference(mongoDb)
.WithReference(redis)
.WaitFor(mongo)
.WaitFor(redis);
.WithReference(mongoDb)
.WithReference(redis)
.WaitFor(mongo)
.WaitFor(redis);

builder.Build().Run();

Expand Down
14 changes: 7 additions & 7 deletions src/Web/Components/Theme/ThemeProvider.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace MyBlog.Web.Components.Theme;

public partial class ThemeProvider : ComponentBase
{
[Inject] private IJSRuntime Js { get; set; } = default!;
[Inject] private IJSRuntime Js { get; set; } = null!;

[Parameter] public RenderFragment? ChildContent { get; set; }

Expand All @@ -27,18 +27,18 @@ protected override async Task OnAfterRenderAsync(bool firstRender)

try
{
CurrentColor = await Js.InvokeAsync<string>("themeManager.getColor");
CurrentColor = await Js.InvokeAsync<string>("themeManager.getColor").ConfigureAwait(true);
}
catch
catch (JSException)
{
// Keep default if localStorage is unavailable
}

try
{
CurrentBrightness = await Js.InvokeAsync<string>("themeManager.getBrightness");
CurrentBrightness = await Js.InvokeAsync<string>("themeManager.getBrightness").ConfigureAwait(true);
}
Comment on lines 28 to 40

Copilot AI Apr 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using .ConfigureAwait(true) on Blazor component code is functionally equivalent to omitting ConfigureAwait and adds noise without benefit. If the goal is to address CA2007 while staying on the renderer context, consider suppressing CA2007 for these IJSRuntime awaits (with a justification) instead of explicitly configuring true everywhere.

Copilot uses AI. Check for mistakes.
catch
catch (JSException)
{
// Keep default if localStorage is unavailable
}
Expand All @@ -50,13 +50,13 @@ public async Task SetColor(string color)
{
CurrentColor = color;
StateHasChanged();
await Js.InvokeVoidAsync("themeManager.setColor", color);
await Js.InvokeVoidAsync("themeManager.setColor", color).ConfigureAwait(true);
}

public async Task SetBrightness(string brightness)
{
CurrentBrightness = brightness;
StateHasChanged();
await Js.InvokeVoidAsync("themeManager.setBrightness", brightness);
await Js.InvokeVoidAsync("themeManager.setBrightness", brightness).ConfigureAwait(true);
}
}
4 changes: 3 additions & 1 deletion src/Web/Data/BlogDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@

namespace MyBlog.Web.Data;

public sealed class BlogDbContext(DbContextOptions<BlogDbContext> options) : DbContext(options)
internal sealed class BlogDbContext(DbContextOptions<BlogDbContext> options) : DbContext(options)
{
public DbSet<BlogPost> BlogPosts => Set<BlogPost>();

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
ArgumentNullException.ThrowIfNull(modelBuilder);

var entity = modelBuilder.Entity<BlogPost>();
entity.ToCollection("blogposts");
entity.HasKey(p => p.Id);
Expand Down
14 changes: 7 additions & 7 deletions src/Web/Data/BlogPostDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
namespace MyBlog.Web.Data;

internal sealed record BlogPostDto(
Guid Id,
string Title,
string Content,
string Author,
DateTime CreatedAt,
DateTime? UpdatedAt,
bool IsPublished);
Guid Id,
string Title,
string Content,
string Author,
DateTime CreatedAt,
DateTime? UpdatedAt,
bool IsPublished);
44 changes: 22 additions & 22 deletions src/Web/Features/BlogPosts/Create/CreateBlogPostHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,28 @@ internal sealed class CreateBlogPostHandler(
IBlogPostRepository repo,
IBlogPostCacheService cache) : IRequestHandler<CreateBlogPostCommand, Result<Guid>>
{
public async Task<Result<Guid>> Handle(CreateBlogPostCommand request, CancellationToken cancellationToken)
{
try
{
var post = BlogPost.Create(request.Title, request.Content, request.Author);
await repo.AddAsync(post, cancellationToken).ConfigureAwait(false);
await cache.InvalidateAllAsync(cancellationToken).ConfigureAwait(false);
return Result.Ok<Guid>(post.Id);
}
catch (OperationCanceledException)
{
throw;
}
catch (InvalidOperationException ex)
{
return Result.Fail<Guid>(ex.Message);
}
public async Task<Result<Guid>> Handle(CreateBlogPostCommand request, CancellationToken cancellationToken)
{
try
{
var post = BlogPost.Create(request.Title, request.Content, request.Author);
await repo.AddAsync(post, cancellationToken).ConfigureAwait(false);
await cache.InvalidateAllAsync(cancellationToken).ConfigureAwait(false);
return Result.Ok<Guid>(post.Id);
}
catch (OperationCanceledException)
{
throw;
}
catch (InvalidOperationException ex)
{
return Result.Fail<Guid>(ex.Message);
}
#pragma warning disable CA1031 // Intentional: top-level handler converts unexpected failures to Result to keep UI stable
catch (Exception)
{
return Result.Fail<Guid>("An unexpected error occurred.");
}
catch (Exception)
{
return Result.Fail<Guid>("An unexpected error occurred.");
}
#pragma warning restore CA1031
}
}
}
56 changes: 28 additions & 28 deletions src/Web/Features/BlogPosts/Delete/DeleteBlogPostHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,34 @@ internal sealed class DeleteBlogPostHandler(
IBlogPostRepository repo,
IBlogPostCacheService cache) : IRequestHandler<DeleteBlogPostCommand, Result>
{
public async Task<Result> Handle(DeleteBlogPostCommand request, CancellationToken cancellationToken)
{
try
{
await repo.DeleteAsync(request.Id, cancellationToken).ConfigureAwait(false);
await cache.InvalidateAllAsync(cancellationToken).ConfigureAwait(false);
await cache.InvalidateByIdAsync(request.Id, cancellationToken).ConfigureAwait(false);
return Result.Ok();
}
catch (DbUpdateConcurrencyException)
{
return Result.Fail(
"This post was modified by another user. Please reload and try again.",
ResultErrorCode.Concurrency);
}
catch (OperationCanceledException)
{
throw;
}
catch (InvalidOperationException ex)
{
return Result.Fail(ex.Message);
}
public async Task<Result> Handle(DeleteBlogPostCommand request, CancellationToken cancellationToken)
{
try
{
await repo.DeleteAsync(request.Id, cancellationToken).ConfigureAwait(false);
await cache.InvalidateAllAsync(cancellationToken).ConfigureAwait(false);
await cache.InvalidateByIdAsync(request.Id, cancellationToken).ConfigureAwait(false);
return Result.Ok();
}
catch (DbUpdateConcurrencyException)
{
return Result.Fail(
"This post was modified by another user. Please reload and try again.",
ResultErrorCode.Concurrency);
}
catch (OperationCanceledException)
{
throw;
}
catch (InvalidOperationException ex)
{
return Result.Fail(ex.Message);
}
#pragma warning disable CA1031 // Intentional: top-level handler converts unexpected failures to Result to keep UI stable
catch (Exception)
{
return Result.Fail("An unexpected error occurred.");
}
catch (Exception)
{
return Result.Fail("An unexpected error occurred.");
}
#pragma warning restore CA1031
}
}
}
116 changes: 58 additions & 58 deletions src/Web/Features/BlogPosts/Edit/EditBlogPostHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,67 +18,67 @@ internal sealed class EditBlogPostHandler(
: IRequestHandler<EditBlogPostCommand, Result>,
IRequestHandler<GetBlogPostByIdQuery, Result<BlogPostDto?>>
{
public async Task<Result> Handle(EditBlogPostCommand request, CancellationToken cancellationToken)
{
try
{
var post = await repo.GetByIdAsync(request.Id, cancellationToken).ConfigureAwait(false);
if (post is null)
return Result.Fail($"BlogPost {request.Id} not found.");
post.Update(request.Title, request.Content);
await repo.UpdateAsync(post, cancellationToken).ConfigureAwait(false);
await cache.InvalidateAllAsync(cancellationToken).ConfigureAwait(false);
await cache.InvalidateByIdAsync(request.Id, cancellationToken).ConfigureAwait(false);
return Result.Ok();
}
catch (DbUpdateConcurrencyException)
{
return Result.Fail(
"This post was modified by another user. Please reload and try again.",
ResultErrorCode.Concurrency);
}
catch (OperationCanceledException)
{
throw;
}
catch (InvalidOperationException ex)
{
return Result.Fail(ex.Message);
}
public async Task<Result> Handle(EditBlogPostCommand request, CancellationToken cancellationToken)
{
try
{
var post = await repo.GetByIdAsync(request.Id, cancellationToken).ConfigureAwait(false);
if (post is null)
return Result.Fail($"BlogPost {request.Id} not found.");
post.Update(request.Title, request.Content);
await repo.UpdateAsync(post, cancellationToken).ConfigureAwait(false);
await cache.InvalidateAllAsync(cancellationToken).ConfigureAwait(false);
await cache.InvalidateByIdAsync(request.Id, cancellationToken).ConfigureAwait(false);
return Result.Ok();
}
catch (DbUpdateConcurrencyException)
{
return Result.Fail(
"This post was modified by another user. Please reload and try again.",
ResultErrorCode.Concurrency);
}
catch (OperationCanceledException)
{
throw;
}
catch (InvalidOperationException ex)
{
return Result.Fail(ex.Message);
}
#pragma warning disable CA1031 // Intentional: top-level handler converts unexpected failures to Result to keep UI stable
catch (Exception)
{
return Result.Fail("An unexpected error occurred.");
}
catch (Exception)
{
return Result.Fail("An unexpected error occurred.");
}
#pragma warning restore CA1031
}
}

public async Task<Result<BlogPostDto?>> Handle(GetBlogPostByIdQuery request, CancellationToken cancellationToken)
{
try
{
var dto = await cache.GetOrFetchByIdAsync(
request.Id,
async () =>
{
var post = await repo.GetByIdAsync(request.Id, cancellationToken).ConfigureAwait(false);
return post?.ToDto();
}, cancellationToken).ConfigureAwait(false);
return Result.Ok<BlogPostDto?>(dto);
}
catch (OperationCanceledException)
{
throw;
}
catch (InvalidOperationException ex)
{
return Result.Fail<BlogPostDto?>(ex.Message);
}
public async Task<Result<BlogPostDto?>> Handle(GetBlogPostByIdQuery request, CancellationToken cancellationToken)
{
try
{
var dto = await cache.GetOrFetchByIdAsync(
request.Id,
async () =>
{
var post = await repo.GetByIdAsync(request.Id, cancellationToken).ConfigureAwait(false);
return post?.ToDto();
}, cancellationToken).ConfigureAwait(false);
return Result.Ok<BlogPostDto?>(dto);
}
catch (OperationCanceledException)
{
throw;
}
catch (InvalidOperationException ex)
{
return Result.Fail<BlogPostDto?>(ex.Message);
}
#pragma warning disable CA1031 // Intentional: top-level handler converts unexpected failures to Result to keep UI stable
catch (Exception)
{
return Result.Fail<BlogPostDto?>("An unexpected error occurred.");
}
catch (Exception)
{
return Result.Fail<BlogPostDto?>("An unexpected error occurred.");
}
#pragma warning restore CA1031
}
}
}
52 changes: 26 additions & 26 deletions src/Web/Features/BlogPosts/List/GetBlogPostsHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,32 @@ internal sealed class GetBlogPostsHandler(
IBlogPostRepository repo,
IBlogPostCacheService cache) : IRequestHandler<GetBlogPostsQuery, Result<IReadOnlyList<BlogPostDto>>>
{
public async Task<Result<IReadOnlyList<BlogPostDto>>> Handle(
GetBlogPostsQuery request, CancellationToken cancellationToken)
{
try
{
var result = await cache.GetOrFetchAllAsync(
async () =>
{
var all = await repo.GetAllAsync(cancellationToken).ConfigureAwait(false);
return (IReadOnlyList<BlogPostDto>)all.Select(p => p.ToDto()).ToList();
}, cancellationToken).ConfigureAwait(false);
return Result.Ok<IReadOnlyList<BlogPostDto>>(result);
}
catch (OperationCanceledException)
{
throw;
}
catch (InvalidOperationException ex)
{
return Result.Fail<IReadOnlyList<BlogPostDto>>(ex.Message);
}
public async Task<Result<IReadOnlyList<BlogPostDto>>> Handle(
GetBlogPostsQuery request, CancellationToken cancellationToken)
{
try
{
var result = await cache.GetOrFetchAllAsync(
async () =>
{
var all = await repo.GetAllAsync(cancellationToken).ConfigureAwait(false);
return (IReadOnlyList<BlogPostDto>)all.Select(p => p.ToDto()).ToList();
}, cancellationToken).ConfigureAwait(false);
return Result.Ok<IReadOnlyList<BlogPostDto>>(result);
}
catch (OperationCanceledException)
{
throw;
}
catch (InvalidOperationException ex)
{
return Result.Fail<IReadOnlyList<BlogPostDto>>(ex.Message);
}
#pragma warning disable CA1031 // Intentional: top-level handler converts unexpected failures to Result to keep UI stable
catch (Exception)
{
return Result.Fail<IReadOnlyList<BlogPostDto>>("An unexpected error occurred.");
}
catch (Exception)
{
return Result.Fail<IReadOnlyList<BlogPostDto>>("An unexpected error occurred.");
}
#pragma warning restore CA1031
}
}
}
Loading
Loading