首页 > 其他分享 >New-Bom-BomService

New-Bom-BomService

时间:2024-12-11 16:20:48浏览次数:9  
标签:BomService MyCc bomHeader Application BOMHeaders Bom using New public

好的,我们将根据之前的内容,专注于实现应用层的 CQRS(命令查询职责分离)模式。CQRS 是一种架构模式,它将读取操作与写入操作分离,通常使用不同的模型来处理命令和查询。我们将使用 MediatR 库来简化 CQRS 的实现,并确保每个部分都清晰明了。

  1. 安装 MediatR

首先,在 MyCc.Application 和 MyCc.WebApi 项目中安装 MediatR 包:

dotnet add package MediatR
dotnet add package MediatR.Extensions.Microsoft.DependencyInjection
  1. 创建命令和查询接口

在 MyCc.Application.Common.Interfaces 文件夹中创建命令和查询接口。

ICommand.cs

namespace MyCc.Application.Common.Interfaces
{
    public interface ICommand
    {
    }
}

IQuery.cs

namespace MyCc.Application.Common.Interfaces
{
    public interface IQuery<T>
    {
    }
}
  1. 创建命令类

在 MyCc.Application.BOMHeaders.Commands 文件夹中创建命令类。

CreateBOMHeaderCommand.cs

using MyCc.Application.Common.Interfaces;
using MyCc.Application.Dtos;

namespace MyCc.Application.BOMHeaders.Commands
{
    public class CreateBOMHeaderCommand : ICommand
    {
        public BOMHeaderDto BOMHeader { get; set; }
    }
}

UpdateBOMHeaderCommand.cs

using MyCc.Application.Common.Interfaces;
using MyCc.Application.Dtos;

namespace MyCc.Application.BOMHeaders.Commands
{
    public class UpdateBOMHeaderCommand : ICommand
    {
        public int BOMID { get; set; }
        public BOMHeaderDto BOMHeader { get; set; }
    }
}

DeleteBOMHeaderCommand.cs

using MyCc.Application.Common.Interfaces;

namespace MyCc.Application.BOMHeaders.Commands
{
    public class DeleteBOMHeaderCommand : ICommand
    {
        public int BOMID { get; set; }
    }
}
  1. 创建查询类

在 MyCc.Application.BOMHeaders.Queries 文件夹中创建查询类。

GetBOMHeadersQuery.cs

using MyCc.Application.Common.Interfaces;
using MyCc.Application.Dtos;
using System.Collections.Generic;

namespace MyCc.Application.BOMHeaders.Queries
{
    public class GetBOMHeadersQuery : IQuery<IEnumerable<BOMHeaderDto>>
    {
    }
}

GetBOMHeaderByIdQuery.cs

using MyCc.Application.Common.Interfaces;
using MyCc.Application.Dtos;

namespace MyCc.Application.BOMHeaders.Queries
{
    public class GetBOMHeaderByIdQuery : IQuery<BOMHeaderDto>
    {
        public int BOMID { get; set; }
    }
}
  1. 创建命令处理器

在 MyCc.Application.BOMHeaders.CommandHandlers 文件夹中创建命令处理器。

CreateBOMHeaderCommandHandler.cs

using MediatR;
using MyCc.Application.BOMHeaders.Commands;
using MyCc.Application.Services;
using System.Threading;
using System.Threading.Tasks;

namespace MyCc.Application.BOMHeaders.CommandHandlers
{
    public class CreateBOMHeaderCommandHandler : IRequestHandler<CreateBOMHeaderCommand, BOMHeaderDto>
    {
        private readonly BOMHeaderService _bomHeaderService;

        public CreateBOMHeaderCommandHandler(BOMHeaderService bomHeaderService)
        {
            _bomHeaderService = bomHeaderService;
        }

        public async Task<BOMHeaderDto> Handle(CreateBOMHeaderCommand request, CancellationToken cancellationToken)
        {
            return await _bomHeaderService.CreateAsync(request.BOMHeader);
        }
    }
}

UpdateBOMHeaderCommandHandler.cs

using MediatR;
using MyCc.Application.BOMHeaders.Commands;
using MyCc.Application.Services;
using System.Threading;
using System.Threading.Tasks;

namespace MyCc.Application.BOMHeaders.CommandHandlers
{
    public class UpdateBOMHeaderCommandHandler : IRequestHandler<UpdateBOMHeaderCommand, bool>
    {
        private readonly BOMHeaderService _bomHeaderService;

        public UpdateBOMHeaderCommandHandler(BOMHeaderService bomHeaderService)
        {
            _bomHeaderService = bomHeaderService;
        }

        public async Task<bool> Handle(UpdateBOMHeaderCommand request, CancellationToken cancellationToken)
        {
            return await _bomHeaderService.UpdateAsync(request.BOMID, request.BOMHeader);
        }
    }
}

DeleteBOMHeaderCommandHandler.cs

using MediatR;
using MyCc.Application.BOMHeaders.Commands;
using MyCc.Application.Services;
using System.Threading;
using System.Threading.Tasks;

namespace MyCc.Application.BOMHeaders.CommandHandlers
{
    public class DeleteBOMHeaderCommandHandler : IRequestHandler<DeleteBOMHeaderCommand, bool>
    {
        private readonly BOMHeaderService _bomHeaderService;

        public DeleteBOMHeaderCommandHandler(BOMHeaderService bomHeaderService)
        {
            _bomHeaderService = bomHeaderService;
        }

        public async Task<bool> Handle(DeleteBOMHeaderCommand request, CancellationToken cancellationToken)
        {
            return await _bomHeaderService.DeleteAsync(request.BOMID);
        }
    }
}
  1. 创建查询处理器

在 MyCc.Application.BOMHeaders.QueryHandlers 文件夹中创建查询处理器。

GetBOMHeadersQueryHandler.cs

using MediatR;
using MyCc.Application.BOMHeaders.Queries;
using MyCc.Application.Services;
using System.Threading;
using System.Threading.Tasks;

namespace MyCc.Application.BOMHeaders.QueryHandlers
{
    public class GetBOMHeadersQueryHandler : IRequestHandler<GetBOMHeadersQuery, IEnumerable<BOMHeaderDto>>
    {
        private readonly BOMHeaderService _bomHeaderService;

        public GetBOMHeadersQueryHandler(BOMHeaderService bomHeaderService)
        {
            _bomHeaderService = bomHeaderService;
        }

        public async Task<IEnumerable<BOMHeaderDto>> Handle(GetBOMHeadersQuery request, CancellationToken cancellationToken)
        {
            return await _bomHeaderService.GetAllAsync();
        }
    }
}

GetBOMHeaderByIdQueryHandler.cs

using MediatR;
using MyCc.Application.BOMHeaders.Queries;
using MyCc.Application.Services;
using System.Threading;
using System.Threading.Tasks;

namespace MyCc.Application.BOMHeaders.QueryHandlers
{
    public class GetBOMHeaderByIdQueryHandler : IRequestHandler<GetBOMHeaderByIdQuery, BOMHeaderDto>
    {
        private readonly BOMHeaderService _bomHeaderService;

        public GetBOMHeaderByIdQueryHandler(BOMHeaderService bomHeaderService)
        {
            _bomHeaderService = bomHeaderService;
        }

        public async Task<BOMHeaderDto> Handle(GetBOMHeaderByIdQuery request, CancellationToken cancellationToken)
        {
            return await _bomHeaderService.GetByIdAsync(request.BOMID);
        }
    }
}
  1. 修改控制器以使用 MediatR

在 MyCc.WebApi.Controllers 文件夹中修改 BOMHeadersController 以使用 MediatR 发送命令和查询。

BOMHeadersController.cs

using MediatR;
using Microsoft.AspNetCore.Mvc;
using MyCc.Application.BOMHeaders.Commands;
using MyCc.Application.BOMHeaders.Queries;
using System.Threading.Tasks;

namespace MyCc.WebApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class BOMHeadersController : ControllerBase
    {
        private readonly IMediator _mediator;

        public BOMHeadersController(IMediator mediator)
        {
            _mediator = mediator;
        }

        // GET: api/BOMHeaders
        [HttpGet]
        public async Task<ActionResult<IEnumerable<BOMHeaderDto>>> GetBOMHeaders()
        {
            var query = new GetBOMHeadersQuery();
            var result = await _mediator.Send(query);
            return Ok(result);
        }

        // GET: api/BOMHeaders/5
        [HttpGet("{id}")]
        public async Task<ActionResult<BOMHeaderDto>> GetBOMHeader(int id)
        {
            var query = new GetBOMHeaderByIdQuery { BOMID = id };
            var result = await _mediator.Send(query);
            if (result == null)
            {
                return NotFound();
            }

            return Ok(result);
        }

        // POST: api/BOMHeaders
        [HttpPost]
        public async Task<ActionResult<BOMHeaderDto>> PostBOMHeader([FromBody] BOMHeaderDto dto)
        {
            var command = new CreateBOMHeaderCommand { BOMHeader = dto };
            var result = await _mediator.Send(command);
            return CreatedAtAction(nameof(GetBOMHeader), new { id = result.BOMID }, result);
        }

        // PUT: api/BOMHeaders/5
        [HttpPut("{id}")]
        public async Task<IActionResult> PutBOMHeader(int id, [FromBody] BOMHeaderDto dto)
        {
            if (id != dto.BOMID)
            {
                return BadRequest();
            }

            var command = new UpdateBOMHeaderCommand { BOMID = id, BOMHeader = dto };
            var updated = await _mediator.Send(command);
            if (!updated)
            {
                return NotFound();
            }

            return NoContent();
        }

        // DELETE: api/BOMHeaders/5
        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteBOMHeader(int id)
        {
            var command = new DeleteBOMHeaderCommand { BOMID = id };
            var deleted = await _mediator.Send(command);
            if (!deleted)
            {
                return NotFound();
            }

            return NoContent();
        }
    }
}
  1. 注册 MediatR 和处理器

在 MyCc.WebApi 项目的 Startup.cs 中注册 MediatR 和所有命令、查询处理器。

Startup.cs

using MediatR;
using MyCc.Application.BOMHeaders.CommandHandlers;
using MyCc.Application.BOMHeaders.QueryHandlers;
using MyCc.Application.Services;
using MyCc.Domain.Repositories;
using MyCc.Infrastructure.Persistence;
using MyCc.Infrastructure.Repositories;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace MyCc.WebApi
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            // 添加数据库上下文
            services.AddDbContext<MyDbContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            // 注册仓储接口和实现
            services.AddScoped<IBOMHeaderRepository, BOMHeaderRepository>();

            // 注册应用服务
            services.AddScoped<BOMHeaderService>();

            // 添加 MediatR 和所有命令、查询处理器
            services.AddMediatR(typeof(Startup));

            // 添加 MVC 和 API 支持
            services.AddControllers();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}
  1. 总结

通过上述步骤,我们已经成功地在 MyCc 项目的应用层实现了 CQRS 模式。具体来说:

  • 命令:用于执行写入操作(如创建、更新、删除),并通过 ICommand 接口定义。
  • 查询:用于执行读取操作(如获取列表、获取单个实体),并通过 IQuery 接口定义。
  • 命令处理器:负责处理命令并调用相应的应用服务。
  • 查询处理器:负责处理查询并返回数据。
  • 控制器:通过 MediatR 发送命令和查询,而不是直接调用应用服务。
  • 依赖注入:通过 Startup.cs 注册 MediatR 和所有命令、查询处理器。

这种结构使得代码更加模块化和易于维护,同时也符合清洁架构和 DDD 的最佳实践。你可以根据项目的具体需求继续扩展和完善各个层次的功能。

如果有更多具体的需求或问题,请随时告知!

好的,接下来我们将继续完善 MyCc 项目,确保其更加健壮、易于维护,并且符合最佳实践。在这一部分中,我们将添加一些常见的功能和模式,如 事件发布/订阅机制验证全局异常处理。这些功能将进一步增强系统的可靠性和用户体验。

  1. 添加事件发布/订阅机制

事件驱动架构(Event-Driven Architecture, EDA)是一种设计模式,它通过事件来解耦系统中的不同组件。我们可以使用 MediatR 来实现领域事件的发布和订阅,从而确保领域逻辑与外部操作(如通知、日志记录等)分离。

14.1 定义领域事件

在 MyCc.Domain.Events 文件夹中创建领域事件类。领域事件通常表示领域模型中发生的重要业务事件。

BOMHeaderCreatedEvent.cs

namespace MyCc.Domain.Events
{
    public class BOMHeaderCreatedEvent
    {
        public int BOMID { get; set; }
        public int ProductID { get; set; }
        public string Type { get; set; }
        public string Usage { get; set; }
        public DateTime CreatedAt { get; set; }
        public string Status { get; set; }
    }
}

BOMHeaderUpdatedEvent.cs

namespace MyCc.Domain.Events
{
    public class BOMHeaderUpdatedEvent
    {
        public int BOMID { get; set; }
        public string NewStatus { get; set; }
    }
}

BOMHeaderDeletedEvent.cs

namespace MyCc.Domain.Events
{
    public class BOMHeaderDeletedEvent
    {
        public int BOMID { get; set; }
    }
}

14.2 修改领域模型以发布事件

我们需要在领域模型中添加事件发布逻辑。每次领域对象发生变化时,都会触发相应的领域事件。我们可以通过一个 DomainEvents 集合来存储这些事件,并在适当的时机发布它们。

BOMHeader.cs

using MyCc.Domain.Events;
using System.Collections.Generic;
using System.Linq;

namespace MyCc.Domain.Entities
{
    public class BOMHeader
    {
        public int BOMID { get; private set; }
        public int ProductID { get; private set; }
        public string Type { get; private set; }
        public string Usage { get; private set; }
        public DateTime CreatedAt { get; private set; }
        public string Status { get; private set; }

        // 现有的构造函数和其他方法...

        private List<IDomainEvent> _domainEvents = new List<IDomainEvent>();
        public IReadOnlyCollection<IDomainEvent> DomainEvents => _domainEvents.AsReadOnly();

        public void AddDomainEvent(IDomainEvent domainEvent)
        {
            _domainEvents.Add(domainEvent);
        }

        public void RemoveDomainEvent(IDomainEvent domainEvent)
        {
            _domainEvents.Remove(domainEvent);
        }

        public void ClearDomainEvents()
        {
            _domainEvents.Clear();
        }

        public void PublishCreatedEvent()
        {
            var eventToPublish = new BOMHeaderCreatedEvent
            {
                BOMID = this.BOMID,
                ProductID = this.ProductID,
                Type = this.Type,
                Usage = this.Usage,
                CreatedAt = this.CreatedAt,
                Status = this.Status
            };
            AddDomainEvent(eventToPublish);
        }

        public void PublishUpdatedEvent(string newStatus)
        {
            var eventToPublish = new BOMHeaderUpdatedEvent
            {
                BOMID = this.BOMID,
                NewStatus = newStatus
            };
            AddDomainEvent(eventToPublish);
        }

        public void PublishDeletedEvent()
        {
            var eventToPublish = new BOMHeaderDeletedEvent
            {
                BOMID = this.BOMID
            };
            AddDomainEvent(eventToPublish);
        }
    }
}

14.3 创建事件处理器

事件处理器负责处理领域事件,并执行相应的业务逻辑。我们可以为每个领域事件创建一个处理器,并使用 MediatR 来订阅这些事件。

BOMHeaderCreatedEventHandler.cs

using MediatR;
using MyCc.Domain.Events;
using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;

namespace MyCc.Application.EventHandlers
{
    public class BOMHeaderCreatedEventHandler : INotificationHandler<BOMHeaderCreatedEvent>
    {
        private readonly ILogger<BOMHeaderCreatedEventHandler> _logger;

        public BOMHeaderCreatedEventHandler(ILogger<BOMHeaderCreatedEventHandler> logger)
        {
            _logger = logger;
        }

        public async Task Handle(BOMHeaderCreatedEvent notification, CancellationToken cancellationToken)
        {
            _logger.LogInformation("BOM Header created with ID: {BOMID}", notification.BOMID);
            // 可以在这里添加其他业务逻辑,例如发送通知、更新缓存等
        }
    }
}

BOMHeaderUpdatedEventHandler.cs

using MediatR;
using MyCc.Domain.Events;
using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;

namespace MyCc.Application.EventHandlers
{
    public class BOMHeaderUpdatedEventHandler : INotificationHandler<BOMHeaderUpdatedEvent>
    {
        private readonly ILogger<BOMHeaderUpdatedEventHandler> _logger;

        public BOMHeaderUpdatedEventHandler(ILogger<BOMHeaderUpdatedEventHandler> logger)
        {
            _logger = logger;
        }

        public async Task Handle(BOMHeaderUpdatedEvent notification, CancellationToken cancellationToken)
        {
            _logger.LogInformation("BOM Header updated with ID: {BOMID}, New Status: {NewStatus}", notification.BOMID, notification.NewStatus);
            // 可以在这里添加其他业务逻辑,例如发送通知、更新缓存等
        }
    }
}

BOMHeaderDeletedEventHandler.cs

using MediatR;
using MyCc.Domain.Events;
using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;

namespace MyCc.Application.EventHandlers
{
    public class BOMHeaderDeletedEventHandler : INotificationHandler<BOMHeaderDeletedEvent>
    {
        private readonly ILogger<BOMHeaderDeletedEventHandler> _logger;

        public BOMHeaderDeletedEventHandler(ILogger<BOMHeaderDeletedEventHandler> logger)
        {
            _logger = logger;
        }

        public async Task Handle(BOMHeaderDeletedEvent notification, CancellationToken cancellationToken)
        {
            _logger.LogInformation("BOM Header deleted with ID: {BOMID}", notification.BOMID);
            // 可以在这里添加其他业务逻辑,例如发送通知、更新缓存等
        }
    }
}

14.4 修改仓储实现以处理事件

在 BOMHeaderRepository 中,我们需要确保在保存实体时发布所有未处理的领域事件。我们可以通过 MediatR 的 Publish 方法来发布这些事件。

BOMHeaderRepository.cs

using MyCc.Domain.Entities;
using MyCc.Domain.Events;
using MyCc.Domain.Repositories;
using MyCc.Infrastructure.Persistence;
using MediatR;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MyCc.Infrastructure.Repositories
{
    public class BOMHeaderRepository : IBOMHeaderRepository
    {
        private readonly MyDbContext _context;
        private readonly IMediator _mediator;

        public BOMHeaderRepository(MyDbContext context, IMediator mediator)
        {
            _context = context;
            _mediator = mediator;
        }

        public async Task<IEnumerable<BOMHeader>> GetAllAsync()
        {
            return await _context.BOMHeaders.ToListAsync();
        }

        public async Task<BOMHeader> GetByIdAsync(int id)
        {
            return await _context.BOMHeaders.FindAsync(id);
        }

        public async Task AddAsync(BOMHeader bomHeader)
        {
            await _context.BOMHeaders.AddAsync(bomHeader);
            bomHeader.PublishCreatedEvent();
            await _mediator.Publish(new DomainEventsNotification(bomHeader.DomainEvents), CancellationToken.None);
            bomHeader.ClearDomainEvents();
            await _context.SaveChangesAsync();
        }

        public async Task UpdateAsync(BOMHeader bomHeader)
        {
            _context.Entry(bomHeader).State = EntityState.Modified;
            bomHeader.PublishUpdatedEvent(bomHeader.Status);
            await _mediator.Publish(new DomainEventsNotification(bomHeader.DomainEvents), CancellationToken.None);
            bomHeader.ClearDomainEvents();
            await _context.SaveChangesAsync();
        }

        public async Task DeleteAsync(int id)
        {
            var bomHeader = await _context.BOMHeaders.FindAsync(id);
            if (bomHeader != null)
            {
                bomHeader.PublishDeletedEvent();
                await _mediator.Publish(new DomainEventsNotification(bomHeader.DomainEvents), CancellationToken.None);
                _context.BOMHeaders.Remove(bomHeader);
                await _context.SaveChangesAsync();
            }
        }
    }
}

DomainEventsNotification.cs

为了简化事件的发布,我们可以创建一个通用的通知类 DomainEventsNotification,它将包含所有需要发布的领域事件。

using MediatR;
using System.Collections.Generic;

namespace MyCc.Application.Common.Notifications
{
    public class DomainEventsNotification : INotification
    {
        public IEnumerable<IDomainEvent> DomainEvents { get; }

        public DomainEventsNotification(IEnumerable<IDomainEvent> domainEvents)
        {
            DomainEvents = domainEvents;
        }
    }
}

14.5 注册事件处理器

在 Startup.cs 中注册所有事件处理器,以便 MediatR 可以自动发现并订阅这些处理器。

Startup.cs

using MediatR;
using MyCc.Application.EventHandlers;
using MyCc.Application.BOMHeaders.CommandHandlers;
using MyCc.Application.BOMHeaders.QueryHandlers;
using MyCc.Application.Services;
using MyCc.Domain.Repositories;
using MyCc.Infrastructure.Persistence;
using MyCc.Infrastructure.Repositories;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace MyCc.WebApi
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            // 添加数据库上下文
            services.AddDbContext<MyDbContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            // 注册仓储接口和实现
            services.AddScoped<IBOMHeaderRepository, BOMHeaderRepository>();

            // 注册应用服务
            services.AddScoped<BOMHeaderService>();

            // 添加 MediatR 和所有命令、查询处理器
            services.AddMediatR(typeof(Startup));

            // 添加 MVC 和 API 支持
            services.AddControllers();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}
  1. 添加验证

为了确保输入数据的有效性,我们可以使用 FluentValidation 库来添加验证逻辑。FluentValidation 是一个流行的库,用于定义复杂的验证规则。

15.1 安装 FluentValidation

在 MyCc.Application 项目中安装 FluentValidation 包:

dotnet add package FluentValidation.AspNetCore

15.2 创建验证规则

在 MyCc.Application.BOMHeaders.Validators 文件夹中创建验证规则类。

BOMHeaderDtoValidator.cs

using FluentValidation;
using MyCc.Application.Dtos;

namespace MyCc.Application.BOMHeaders.Validators
{
    public class BOMHeaderDtoValidator : AbstractValidator<BOMHeaderDto>
    {
        public BOMHeaderDtoValidator()
        {
            RuleFor(x => x.ProductID).GreaterThan(0).WithMessage("ProductID must be greater than 0.");
            RuleFor(x => x.Type).NotEmpty().WithMessage("Type is required.");
            RuleFor(x => x.Usage).NotEmpty().WithMessage("Usage is required.");
            RuleFor(x => x.Status).NotEmpty().WithMessage("Status is required.");
        }
    }
}

15.3 注册验证器

在 Startup.cs 中注册 FluentValidation 验证器。

Startup.cs

using FluentValidation;
using FluentValidation.AspNetCore;
using MyCc.Application.BOMHeaders.Validators;

public void ConfigureServices(IServiceCollection services)
{
    // 其他配置...

    // 添加 FluentValidation
    services.AddFluentValidationAutoValidation();
    services.AddFluentValidationClientsideAdapters();
    services.AddScoped<IValidator<BOMHeaderDto>, BOMHeaderDtoValidator>();

    // 其他依赖注入...
}
  1. 添加全局异常处理

为了统一处理应用程序中的异常,我们可以在 MyCc.WebApi 项目中添加全局异常处理中间件。这将确保所有未捕获的异常都能被正确处理,并返回友好的错误信息给客户端。

16.1 创建异常处理中间件

在 MyCc.WebApi.Middleware 文件夹中创建 ExceptionMiddleware.cs 文件。

ExceptionMiddleware.cs

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using System.Net;
using System.Threading.Tasks;

namespace MyCc.WebApi.Middleware
{
    public class ExceptionMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<ExceptionMiddleware> _logger;

        public ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }

        public async Task InvokeAsync(HttpContext httpContext)
        {
            try
            {
                await _next(httpContext);
            }
            catch (Exception ex)
            {
                _logger.LogError($"Something went wrong: {ex.Message}");
                await HandleExceptionAsync(httpContext, ex);
            }
        }

        private Task HandleExceptionAsync(HttpContext context, Exception exception)
        {
            context.Response.ContentType = "application/json";
            context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

            return context.Response.WriteAsync(new
            {
                StatusCode = context.Response.StatusCode,
                Message = "Internal Server Error from the custom middleware."
            }.ToString());
        }
    }
}

16.2 使用异常处理中间件

在 Startup.cs 中使用异常处理中间件。

Startup.cs

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseMiddleware<ExceptionMiddleware>();
    }

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}
  1. 总结

通过上述步骤,我们进一步增强了 MyCc 项目的功能和结构:

  • 事件发布/订阅机制:通过领域事件和 MediatR 实现了事件驱动架构,确保领域逻辑与外部操作分离。
  • 验证:使用 FluentValidation 添加了输入验证,确保传入的数据符合业务规则。
  • 全局异常处理:通过自定义中间件实现了全局异常处理,确保所有未捕获的异常都能被正确处理并返回友好的错误信息。

这种结构不仅提高了代码的可维护性和可测试性,还使得系统更加模块化和易于扩展。你可以根据项目的具体需求继续扩展和完善各个层次的功能。

如果有更多具体的需求或问题,请随时告知!

好的,我们将为 BOMHeaderService 补充代码。这个服务将作为应用层的一部分,负责协调领域逻辑和基础设施之间的交互。它将使用仓储接口来与数据库进行交互,并确保业务规则得到正确执行。

  1. 创建 BOMHeaderService

在 MyCc.Application.Services 文件夹中创建 BOMHeaderService.cs 文件。

BOMHeaderService.cs

using MyCc.Application.Dtos;
using MyCc.Domain.Entities;
using MyCc.Domain.Repositories;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MyCc.Application.Services
{
    public class BOMHeaderService
    {
        private readonly IBOMHeaderRepository _bomHeaderRepository;

        public BOMHeaderService(IBOMHeaderRepository bomHeaderRepository)
        {
            _bomHeaderRepository = bomHeaderRepository;
        }

        /// <summary>
        /// 获取所有 BOMHeader 的列表。
        /// </summary>
        /// <returns>BOMHeaderDto 的集合。</returns>
        public async Task<IEnumerable<BOMHeaderDto>> GetAllAsync()
        {
            var bomHeaders = await _bomHeaderRepository.GetAllAsync();
            return bomHeaders.Select(MapToDto);
        }

        /// <summary>
        /// 根据 ID 获取 BOMHeader。
        /// </summary>
        /// <param name="id">BOMHeader 的 ID。</param>
        /// <returns>BOMHeaderDto 或 null(如果未找到)。</returns>
        public async Task<BOMHeaderDto> GetByIdAsync(int id)
        {
            var bomHeader = await _bomHeaderRepository.GetByIdAsync(id);
            return bomHeader != null ? MapToDto(bomHeader) : null;
        }

        /// <summary>
        /// 创建新的 BOMHeader。
        /// </summary>
        /// <param name="dto">包含新 BOMHeader 信息的 DTO。</param>
        /// <returns>创建的 BOMHeaderDto。</returns>
        public async Task<BOMHeaderDto> CreateAsync(BOMHeaderDto dto)
        {
            var bomHeader = MapToEntity(dto);
            await _bomHeaderRepository.AddAsync(bomHeader);
            return MapToDto(bomHeader);
        }

        /// <summary>
        /// 更新现有的 BOMHeader。
        /// </summary>
        /// <param name="id">要更新的 BOMHeader 的 ID。</param>
        /// <param name="dto">包含更新信息的 DTO。</param>
        /// <returns>更新是否成功。</returns>
        public async Task<bool> UpdateAsync(int id, BOMHeaderDto dto)
        {
            var existingBomHeader = await _bomHeaderRepository.GetByIdAsync(id);
            if (existingBomHeader == null)
            {
                return false;
            }

            // 更新实体属性
            existingBomHeader.ProductID = dto.ProductID;
            existingBomHeader.Type = dto.Type;
            existingBomHeader.Usage = dto.Usage;
            existingBomHeader.Status = dto.Status;

            await _bomHeaderRepository.UpdateAsync(existingBomHeader);
            return true;
        }

        /// <summary>
        /// 删除指定 ID 的 BOMHeader。
        /// </summary>
        /// <param name="id">要删除的 BOMHeader 的 ID。</param>
        /// <returns>删除是否成功。</returns>
        public async Task<bool> DeleteAsync(int id)
        {
            var bomHeader = await _bomHeaderRepository.GetByIdAsync(id);
            if (bomHeader == null)
            {
                return false;
            }

            await _bomHeaderRepository.DeleteAsync(id);
            return true;
        }

        /// <summary>
        /// 将 BOMHeader 实体映射为 DTO。
        /// </summary>
        /// <param name="entity">BOMHeader 实体。</param>
        /// <returns>BOMHeaderDto。</returns>
        private static BOMHeaderDto MapToDto(BOMHeader entity)
        {
            return new BOMHeaderDto
            {
                BOMID = entity.BOMID,
                ProductID = entity.ProductID,
                Type = entity.Type,
                Usage = entity.Usage,
                CreatedAt = entity.CreatedAt,
                Status = entity.Status
            };
        }

        /// <summary>
        /// 将 DTO 映射为 BOMHeader 实体。
        /// </summary>
        /// <param name="dto">BOMHeaderDto。</param>
        /// <returns>BOMHeader 实体。</returns>
        private static BOMHeader MapToEntity(BOMHeaderDto dto)
        {
            return new BOMHeader
            {
                BOMID = dto.BOMID,
                ProductID = dto.ProductID,
                Type = dto.Type,
                Usage = dto.Usage,
                CreatedAt = dto.CreatedAt,
                Status = dto.Status
            };
        }
    }
}
  1. 创建 DTO 类

在 MyCc.Application.Dtos 文件夹中创建 BOMHeaderDto.cs 文件,用于定义数据传输对象(DTO),以便在应用层和外部之间传递数据。

BOMHeaderDto.cs

namespace MyCc.Application.Dtos
{
    public class BOMHeaderDto
    {
        public int BOMID { get; set; }
        public int ProductID { get; set; }
        public string Type { get; set; }
        public string Usage { get; set; }
        public DateTime CreatedAt { get; set; }
        public string Status { get; set; }
    }
}
  1. 修改仓储接口

确保 IBOMHeaderRepository 接口定义了所有必要的方法。你可以在 MyCc.Domain.Repositories 文件夹中找到该接口。

IBOMHeaderRepository.cs

using MyCc.Domain.Entities;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MyCc.Domain.Repositories
{
    public interface IBOMHeaderRepository
    {
        Task<IEnumerable<BOMHeader>> GetAllAsync();
        Task<BOMHeader> GetByIdAsync(int id);
        Task AddAsync(BOMHeader bomHeader);
        Task UpdateAsync(BOMHeader bomHeader);
        Task DeleteAsync(int id);
    }
}
  1. 修改仓储实现

确保 BOMHeaderRepository 实现了 IBOMHeaderRepository 接口中的所有方法。你可以在 MyCc.Infrastructure.Repositories 文件夹中找到该类。

BOMHeaderRepository.cs

using MyCc.Domain.Entities;
using MyCc.Domain.Repositories;
using MyCc.Infrastructure.Persistence;
using MediatR;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MyCc.Infrastructure.Repositories
{
    public class BOMHeaderRepository : IBOMHeaderRepository
    {
        private readonly MyDbContext _context;
        private readonly IMediator _mediator;

        public BOMHeaderRepository(MyDbContext context, IMediator mediator)
        {
            _context = context;
            _mediator = mediator;
        }

        public async Task<IEnumerable<BOMHeader>> GetAllAsync()
        {
            return await _context.BOMHeaders.ToListAsync();
        }

        public async Task<BOMHeader> GetByIdAsync(int id)
        {
            return await _context.BOMHeaders.FindAsync(id);
        }

        public async Task AddAsync(BOMHeader bomHeader)
        {
            await _context.BOMHeaders.AddAsync(bomHeader);
            bomHeader.PublishCreatedEvent();
            await _mediator.Publish(new DomainEventsNotification(bomHeader.DomainEvents), CancellationToken.None);
            bomHeader.ClearDomainEvents();
            await _context.SaveChangesAsync();
        }

        public async Task UpdateAsync(BOMHeader bomHeader)
        {
            _context.Entry(bomHeader).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
            bomHeader.PublishUpdatedEvent(bomHeader.Status);
            await _mediator.Publish(new DomainEventsNotification(bomHeader.DomainEvents), CancellationToken.None);
            bomHeader.ClearDomainEvents();
            await _context.SaveChangesAsync();
        }

        public async Task DeleteAsync(int id)
        {
            var bomHeader = await _context.BOMHeaders.FindAsync(id);
            if (bomHeader != null)
            {
                bomHeader.PublishDeletedEvent();
                await _mediator.Publish(new DomainEventsNotification(bomHeader.DomainEvents), CancellationToken.None);
                _context.BOMHeaders.Remove(bomHeader);
                await _context.SaveChangesAsync();
            }
        }
    }
}
  1. 注册依赖注入

确保在 Startup.cs 中注册 BOMHeaderService 和其他依赖项。

Startup.cs

using MediatR;
using MyCc.Application.BOMHeaders.CommandHandlers;
using MyCc.Application.BOMHeaders.QueryHandlers;
using MyCc.Application.Services;
using MyCc.Domain.Repositories;
using MyCc.Infrastructure.Persistence;
using MyCc.Infrastructure.Repositories;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace MyCc.WebApi
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            // 添加数据库上下文
            services.AddDbContext<MyDbContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            // 注册仓储接口和实现
            services.AddScoped<IBOMHeaderRepository, BOMHeaderRepository>();

            // 注册应用服务
            services.AddScoped<BOMHeaderService>();

            // 添加 MediatR 和所有命令、查询处理器
            services.AddMediatR(typeof(Startup));

            // 添加 MVC 和 API 支持
            services.AddControllers();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}
  1. 总结

通过上述步骤,我们已经为 BOMHeaderService 补充了完整的代码:

  • BOMHeaderService:负责协调领域逻辑和基础设施之间的交互,提供了获取、创建、更新和删除 BOMHeader 的方法。
  • BOMHeaderDto:用于在应用层和外部之间传递数据的 DTO 类。
  • IBOMHeaderRepository:定义了仓储接口,确保与数据库的交互是通过接口进行的,便于测试和维护。
  • BOMHeaderRepository:实现了 IBOMHeaderRepository 接口,负责与数据库进行实际的交互。
  • 依赖注入:确保 BOMHeaderService 和其他依赖项在应用程序启动时被正确注册。

这种结构使得代码更加模块化和易于维护,同时也符合清洁架构和 DDD 的最佳实践。你可以根据项目的具体需求继续扩展和完善各个层次的功能。

如果有更多具体的需求或问题,请随时告知!

标签:BomService,MyCc,bomHeader,Application,BOMHeaders,Bom,using,New,public
From: https://www.cnblogs.com/eqycc/p/18599881

相关文章

  • CS211 Defusing a Binary Bomb
    CS211: Fall 2024Defusing a Binary BombDue: December 15th,2024CS211Sections 5 - 81    IntroductionThe nefarious Dr. Evil has planted a slew of “binary bombs” on our class machines. A binary bomb is a programthatconsis......
  • CF2029C New Rating
    思路(二分+数据结构优化DP)大致题意为:一个值\(x\)初始为\(0\),然后有一个数组\(a\),遍历一次数组。如果\(a_i>x\),则\(x+1\)。如果\(a_i<x\),则\(x-1\)。如果\(a_i=x\),则\(x\)不变。必须且只能跨越一段连续区间,求\(x\)的最大可能值。后面的由前面的计算......
  • NewStar CTF 2024-week1-web
    headach3题目提示:head我们右键点查看,在网络处添加HEAD请求头就得到了flag:flag{You_Ar3_R3Ally_A_9ooD_d0ctor}会赢吗查看页面源代码,得到flag第一部分:ZmxhZ3tXQTB3继续访问/4cqu1siti0n查看页面源代码我们使用post方法请求接口,得到第二部分flag:IV95NF9yM2Fs我们继续......
  • 为什么 super().__new__(cls, name, bases, dct) 中的 cls 是显式传递的,而不是像 self
    问题来源:为什么定义元类和自定义元类时,在调用父类的__new__方法时都是需要显式传递cls的,而__init__在调用父类__init__方法时就是隐式的。#自定义元类classMyMeta(type):def__new__(cls,name,bases,dct):print(f"Creatingclass{name}usingMyMeta")......
  • [NewStarCTF 公开赛赛道]HTTP
    [NewStarCTF公开赛赛道]HTTPGET方式传入name源代码里发现key修改cookie......
  • 一个js文件导出一个new class实例,其他多个地方import引用的是同一个实例对象吗
    在JavaScript中,当你从一个模块导出一个类的实例时,其他模块在导入这个实例时将获得该实例的一个引用。这意味着,如果你修改了这个实例的属性或调用它的方法,所有导入该实例的模块都会看到这些更改,因为它们引用的是同一个对象。以下是一个示例:moduleA.js:classMyClass{const......
  • new,apply,call,bind方法
    newnew被调用后做了什么创建一个空对象,该对象的__proto__属性应该指向new调用的构造函数的prototype将this指向这个空对象执行new调用的构造函数代码块内容根据调用的构造函数是否有返回值判断,如果返回值存在且typeof检测类型为object类型,则返回该结果,如果不存在返回值或者......
  • 深入解析 `Proxy.newProxyInstance` 方法的三个参数
    深入解析Proxy.newProxyInstance方法的三个参数在Java中,动态代理是通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来实现的。Proxy.newProxyInstance方法是创建动态代理实例的核心。为了更好地理解这个方法及其参数,我们将逐一探讨每个参数的作用,并结......
  • 【Spring 全家桶】 Spring IOC & DI 保姆式教学, 教你不用new也能获取到对象的依赖注入
    本篇会加入个人的所谓鱼式疯言❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言而是理解过并总结出来通俗易懂的大白话,小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.......
  • 在 docker 容器中运行 python 程序,报错:"RuntimeError: can't start new thread"
    具体报错信息如下所示:Traceback(mostrecentcalllast):File"/usr/local/lib/python3.12/site-packages/uvicorn/protocols/http/h11_impl.py",line406,inrun_asgiresult=awaitapp(#type:ignore[func-returns-value]^^^^^^^^^^^^^^^^^^......