我的 .NET Core/Blazor 架构中的服务层是多余的吗?

问题描述 投票:0回答:2

我有一个数据访问层(一个 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 命令而没有任何问题。

c# .net-core blazor dbcontext data-access-layer
2个回答
0
投票

我有一个 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 的范围。


0
投票

在设计中,您需要考虑三个基本层次:

  1. 基础设施:关于如何获取和保存数据。
  2. 核心/业务:您的业务逻辑和对象所在的位置。
  3. 演示:您的 UI 界面。

它们之间的基本关系是这样的:

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/

© www.soinside.com 2019 - 2024. All rights reserved.