我有一个数据访问层(一个 C# 库),一个我打算用作服务的 .NET Core 应用程序和几个需要与该服务对话的项目,包括一个 Blazor WASM 项目。
我的 DAL 有一个如下所示的 DbContext:
public class QualityAssuranceDbContext : DbContext
{
public QualityAssuranceDbContext(DbContextOptions<QualityAssuranceDbContext> options)
: base(options)
{
}
public QualityAssuranceDbContext()
{
}
public DbSet<Aspect> Aspects { get; set; }
//PLUS OTHER ENTITIES REDACTED FOR BREVITY
}
在我的 .NET Core 服务层中,我有一个 BaseRepository、一个 UnitOfWork 和一个服务类,目前看起来像这样:
public class QualityAssuranceService : IQualityAssuranceService
{
private readonly IUnitOfWorkQA _unitOfWork;
private static HttpContext _httpContext => new HttpContextAccessor().HttpContext;
public QualityAssuranceService(IUnitOfWorkQA unitOfWork)
{
_unitOfWork = unitOfWork;
}
public async Task<IEnumerable<AspectDto>> GetAspects(int schoolId, bool includeDeleted = false)
{
var aspects = await _unitOfWork.Aspects.GetAll(
expression: q =>
q.SchoolId == schoolId &&
q.Enabled == true,
orderBy: o => o
.OrderBy(x => x.Name));
var aspectsDto = (from aspect in aspects
select new AspectDto()
{
Id = aspect.Id,
Name = aspect.Name,
SchoolId = aspect.SchoolId,
}).ToList();
return aspectsDto;
}
//PLUS OTHER ACTIONS REDACTED FOR BREVITY
public void Dispose()
{
_unitOfWork.Dispose();
GC.SuppressFinalize(this);
}
}
最后,在我的 Blazor 应用程序中,我的服务器项目中有一个
Program.cs
文件,如下所示:
public partial class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
//REDACTED AS IRRELEVANT TO QUESTION
var QualityAssuranceConnectionString = builder.Configuration.GetConnectionString("QualityAssuranceConnection");
builder.Services.AddDbContext<QualityAssuranceDbContext>(options =>
{
options.UseSqlServer(QualityAssuranceConnectionString);
options.EnableSensitiveDataLogging(true);
});
builder.Services.AddTransient<IUnitOfWorkQA, UnitOfWorkQA>();
builder.Services.AddTransient<IQualityAssuranceService, QualityAssuranceService>();
var app = builder.Build();
//REDACTED AS IRRELEVANT TO QUESTION
app.Run();
}
}
和一个像这样注入服务的控制器:
public class QualityAssuranceController : ControllerBase
{
private readonly IQualityAssuranceService _qualityAssuranceService;
public QualityAssuranceController(IQualityAssuranceService qualityAssuranceService)
{
_qualityAssuranceService = qualityAssuranceService;
}
[HttpGet]
public async Task<IActionResult> GetAspects(bool includeDeleted = false)
{
var schoolId = GetSchoolId();
var aspectDtos = await _qualityAssuranceService.GetAspects(schoolId, includeDeleted);
return Ok(aspectDtos);
}
}
我的问题是:在这种情况下,.NET Core 服务应用程序是冗余的吗?我问的原因是因为我最初打算让 .NET Core 服务应用程序包含数据库的连接字符串并在其
Program.cs
文件中注册 DbContext。但是,我很快意识到,如果不在我的 Blazor Program.cs
文件中注册 UnitOfWork 和 DbContext,我就无法将服务注入我的 Blazor 控制器。
该服务将被我的 Blazor 应用程序和另一个 .NET Core 应用程序引用,因此它很有用,因为它可以防止我们不得不复制一些代码,但我认为该层的目的也是添加一个抽象级别在我的 Blazor 应用程序和数据库之间——如果与数据库的连接在我的 Blazor 应用程序中,那肯定不是这里发生的事情?
我现在应该补充一点,这一切都有效,因为我能够从我的 Blazor 应用程序连接到数据库并执行基本的 CRUD 命令而没有任何问题。
我有一个 MVC 应用程序,其中包含我构建的复杂日历组件。有类似的问题,因为我已经有一个服务层,每个服务都注入了 dbcontext,我想重用它而不是直接使用 dbContext 或在 Blazor Server 中使用 HTTPClient 做一些奇怪的事情。
我的解决方案是使用:
[Inject] private IServiceScopeFactory ServiceScopeFactory { get; set; }
private async Task OnSubmit()
{
using (IServiceScope scope = scopeFactory.CreateScope())
{
ITenantService tenantService = scope.ServiceProvider.GetRequiredService<ITenantService>();
IUserService userService = scope.ServiceProvider.GetRequiredService<IUserService>();
IAppointmentService appointmentService = scope.ServiceProvider.GetRequiredService<IAppointmentService>();
ITimesheetService timesheetService = scope.ServiceProvider.GetRequiredService<ITimesheetService>();
// all logic using services
}
}
这样我创建了一个单独的范围,获取服务。直接去 DI 对我不起作用,因为 SignalR 不喜欢我的 servives/dbcontext 的范围。
在设计中,您需要考虑三个基本层次:
它们之间的基本关系是这样的:
Presentation =>核心/业务<= Infratructure
核心不依赖任何人。演示文稿不了解基础设施对象,反之亦然。
各层都有服务
核心/业务领域通过接口定义它与基础架构领域的契约。基础设施领域提供了这些接口的实现。
Presentation 域可以直接调用您的核心/业务域,因此实际上不需要接口。我使用
Presenters
将数据呈现给表示层:WeatherForecastListPresenter
为 FetchData
提供必要的数据和状态管理。
在您的特定情况下,控制器是表示层:它将数据呈现给外界。你的
Service
层是你的核心域,你的DAL是基础设施。
将服务层和基础设施层视为数据管道。他们可以向 Blazor 服务器应用程序和 SSR 应用程序、服务器 API 应用程序提供数据,...
Blazor 与大多数 SPA 和现代应用程序一样,旨在在异步世界中运行。大多数现代数据存储和 HttpClients 也是异步的。
您需要在您的基础架构域代码中考虑到这一点。数据库的解决方案是使用 DbContext Factory 和 API 调用 HttpContext Factory。使用 DbContext Factory 可以简化工作单元的实现。
这里有一个关于这个话题的有趣讨论-https://garywoodfine.com/generic-repository-pattern-net-core/