【C#】ABP框架服务端开发

系列文章

【C#】最全业务单据号生成(支持定义规则、流水号、传参数)

本文链接:https://blog.csdn.net/youcheng_ge/article/details/129129787

【C#】日期范围生成器(开始日期、结束日期)

本文链接:https://blog.csdn.net/youcheng_ge/article/details/129040663

【C#】组件化开发,调用dll组件方法

本文链接:https://blog.csdn.net/youcheng_ge/article/details/129492112


文章目录

  • 系列文章
  • 前言
  • 一、问题描述
  • 二、解决方案
  • 三、软件开发(源码)
    • [3.1 服务端命令行](#3.1 服务端命令行)
    • [3.2 Step.MmsNT.DbMigrator](#3.2 Step.MmsNT.DbMigrator)
    • [3.3 Step.MmsNT.Domain领域实体](#3.3 Step.MmsNT.Domain领域实体)
    • [3.4 Step.MmsNT.EntityFrameworkCore轻量级跨平台EF Core框架](#3.4 Step.MmsNT.EntityFrameworkCore轻量级跨平台EF Core框架)
    • [3.5 Step.MmsNT.Application应用服务](#3.5 Step.MmsNT.Application应用服务)
    • [3.6 Step.MmsNT.Application.Contracts按钮权限](#3.6 Step.MmsNT.Application.Contracts按钮权限)
    • [3.7 Step.MmsNT.Domain.Shared国际化多语言](#3.7 Step.MmsNT.Domain.Shared国际化多语言)
  • 四、项目展示
  • 五、资源链接

前言

【C# 项目实战】​ 拒绝枯燥理论,只讲落地干货!

本专栏收纳我在实际开发中总结的成熟解决方案,涵盖各类业务场景与疑难杂症。文章结构调整为「问题描述 -> 项目展示 -> 解决方案」,让你一眼看懂代码能做什么。所有案例均经过生产环境验证(已规避商业机密),旨在提供高复用性的处理逻辑。代码力求精简高效,专栏持续更新,欢迎关注,一起用C#征服复杂业务!

·提示:本专栏为项目实战篇,未接触项目开发的同学可能理解困难,不推荐阅读。


一、问题描述

MmsNT_Server 是后端,基于 .NET 10 + ABP 10.3,负责接口、登录认证、权限、数据库、业务逻辑。

MmsNT_Client 是主要前端,基于 Vue 3 + Vite + TypeScript + Vben Admin + Ant Design Vue,负责后台管理页面。

二、解决方案

遵循 ABP 分层 DDD:

Domain.Shared 放常量、枚举、本地化、ETO;

Domain 放实体、聚合根、领域服务、仓储接口;

Application.Contracts 放 DTO 和服务接口;

Application 放应用服务实现和映射;

EntityFrameworkCore 放 DbContext、仓储实现、迁移;

HttpApi 只在不用 Auto API 时写 Controller;

DbMigrator 负责迁移和种子数据。

三、软件开发(源码)

3.1 服务端命令行

项目初始化,在Developer PowerShell

bash 复制代码
abp install-libs

项目启动项

bash 复制代码
Step.MmsNT.HttpApi.Host

3.2 Step.MmsNT.DbMigrator

重新生成表结构,需要运行一下,生成初始化默认数据,否则无法登陆。

3.3 Step.MmsNT.Domain领域实体

手动,创建数据库表实体

Step.MmsNT.Domain\BasicData

3.4 Step.MmsNT.EntityFrameworkCore轻量级跨平台EF Core框架

E:\MyProject\mms\mms_server\src\Step.MmsNT.EntityFrameworkCore\Migrations\20260605033026_AddTAX_0009.cs

自动生成数据库CRUD命令

bash 复制代码
Add-Migration AddTAX_0009
Update-Database

AddTAX_0009

c# 复制代码
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;

#nullable disable

namespace Step.MmsNT.Migrations
{
    /// <inheritdoc />
    public partial class AddTAX_0009 : Migration
    {
        /// <inheritdoc />
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "TAX_0009",
                columns: table => new
                {
                    Id = table.Column<int>(type: "integer", nullable: false, comment: "主键")
                        .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
                    C_IS_USING = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false, comment: "有效标识"),
                    C_MACHINE_CD = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false, comment: "机台/产线/机台组 码号/身份"),
                    C_MACHINE_NM = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false, comment: "机台/产线/机台组 名称"),
                    C_SIM_MACHINE_CD = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false, comment: "机台简码"),
                    C_PLAN_NO = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false, comment: "作业计划"),
                    C_FATHER_MACHINE_ID = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false, comment: "机台父编码"),
                    N_MACHINE_FIRST_FEW = table.Column<long>(type: "bigint", nullable: false, comment: "第几台"),
                    N_LAYER_LEVEL = table.Column<long>(type: "bigint", nullable: false, comment: "层级"),
                    C_PLANT_CD = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false, comment: "实体工厂"),
                    C_PROC_CD = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false, comment: "工序代码"),
                    C_MACHINE_FORM = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false, comment: "机台形态"),
                    N_SEQ_NO = table.Column<long>(type: "bigint", nullable: false, comment: "顺序号"),
                    C_REMARK = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true, comment: "备注"),
                    C_PRO_STATE = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false, comment: "生产状态"),
                    C_MANU = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false, comment: "厂商"),
                    C_MODEL = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false, comment: "型号"),
                    C_MACHINE_TYPE = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false, comment: "机台类型"),
                    C_WORKSHOP_NO = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false, comment: "所属车间编码"),
                    C_WORK_CENTER = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false, comment: "生产工作中心编码"),
                    C_MACHINE_PID = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false, comment: "机台父主键"),
                    C_AUTHORITY_GROUP_ID = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true, comment: "授权用户组ID"),
                    ExtraProperties = table.Column<string>(type: "text", nullable: false, comment: "扩展属性"),
                    ConcurrencyStamp = table.Column<string>(type: "character varying(40)", maxLength: 40, nullable: false, comment: "并发标识"),
                    CreationTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: false, comment: "创建时间"),
                    CreatorId = table.Column<Guid>(type: "uuid", nullable: true, comment: "创建人ID"),
                    LastModificationTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: true, comment: "最后修改时间"),
                    LastModifierId = table.Column<Guid>(type: "uuid", nullable: true, comment: "最后修改人ID"),
                    IsDeleted = table.Column<bool>(type: "boolean", nullable: false, defaultValue: false, comment: "是否删除"),
                    DeleterId = table.Column<Guid>(type: "uuid", nullable: true, comment: "删除人ID"),
                    DeletionTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: true, comment: "删除时间")
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_TAX_0009", x => x.Id);
                },
                comment: "产线机台主数据");
        }

        /// <inheritdoc />
        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "TAX_0009");
        }
    }
}

MmsNTDbContext.cs

如果不添加,TAX_2036AutoMapperProfile 会找不到引用

c# 复制代码
public DbSet<TAX_2036> TAX_2036 { get; set; }

3.5 Step.MmsNT.Application应用服务

E:\MyProject\mms\mms_server\src\Step.MmsNT.Application\TAX_2036Service\TAX_2036Dtos\CreateUpdateTAX_2036Dto.cs

CreateUpdateTAX_2036Dto创建更新(新增修改)DTO

c# 复制代码
using System.ComponentModel.DataAnnotations;

namespace Step.MmsNT.TAX_2036Service;

public class CreateUpdateTAX_2036Dto
{
    [Required]
    [StringLength(512)]
    public string CPlantId { get; set; } = string.Empty;

    [Required]
    [StringLength(512)]
    public string CStoreHouse { get; set; } = string.Empty;

    [Required]
    [StringLength(30)]
    public string CStoLocation { get; set; } = string.Empty;

    [Required]
    [StringLength(30)]
    public string CStoType { get; set; } = string.Empty;

    [StringLength(10)]
    public string? CTlDj { get; set; }

    [StringLength(30)]
    public string? CStoLocationTxt { get; set; }

    [StringLength(100)]
    public string? CRemark { get; set; }

    [Required]
    [StringLength(10)]
    public string CIsUse { get; set; } = "Y";
}

E:\MyProject\mms\mms_server\src\Step.MmsNT.Application\TAX_2036Service\TAX_2036Dtos\GetTAX_2036ListInput.cs

GetTAX_2036ListInput输入(查询)参数DTO

c# 复制代码
using Volo.Abp.Application.Dtos;

namespace Step.MmsNT.TAX_2036Service;

public class GetTAX_2036ListInput : PagedAndSortedResultRequestDto
{
    public string? CPlantId { get; set; }

    public string? CStoreHouse { get; set; }

    public string? CStoLocation { get; set; }

    public string? CStoType { get; set; }

    public string? CStoLocationTxt { get; set; }

    public bool IncludeInvalidData { get; set; }
}

E:\MyProject\mms\mms_server\src\Step.MmsNT.Application\TAX_2036Service\TAX_2036Dtos\ITAX_2036AppService.cs

ITAX_2036AppService服务接口

c# 复制代码
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;

namespace Step.MmsNT.TAX_2036Service;

public interface ITAX_2036AppService :
    ICrudAppService<
        TAX_2036Dto,
        int,
        GetTAX_2036ListInput,
        CreateUpdateTAX_2036Dto>
{
}

E:\MyProject\mms\mms_server\src\Step.MmsNT.Application\TAX_2036Service\TAX_2036Dtos\TAX_2036Dto.cs

TAX_2036Dto输出(结果)参数DTO

c# 复制代码
using Volo.Abp.Application.Dtos;

namespace Step.MmsNT.TAX_2036Service;

public class TAX_2036Dto : AuditedEntityDto<int>
{
    public string CPlantId { get; set; } = string.Empty;

    public string CStoreHouse { get; set; } = string.Empty;

    public string CStoLocation { get; set; } = string.Empty;

    public string CStoType { get; set; } = string.Empty;

    public string? CTlDj { get; set; }

    public string? CStoLocationTxt { get; set; }

    public string? CRemark { get; set; }

    public string CIsUse { get; set; } = string.Empty;
}

E:\MyProject\mms\mms_server\src\Step.MmsNT.Application\TAX_2036Service\TAX_2036AppService.cs

TAX_2036AppService服务方法实现

c# 复制代码
using Microsoft.AspNetCore.Authorization;
using Step.MmsNT.BasicData;
using Step.MmsNT.Permissions;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;

namespace Step.MmsNT.TAX_2036Service;

[Authorize(MmsNTPermissions.Mes.BasicData.TAX_2036.Default)]
public class TAX_2036AppService : MmsNTAppService, ITAX_2036AppService
{
    private readonly IRepository<TAX_2036, int> _repository;

    public TAX_2036AppService(IRepository<TAX_2036, int> repository)
    {
        _repository = repository;
    }

    public async Task<TAX_2036Dto> GetAsync(int id)
    {
        var storageLocation = await _repository.GetAsync(id);
        return ObjectMapper.Map<TAX_2036, TAX_2036Dto>(storageLocation);
    }

    public async Task<PagedResultDto<TAX_2036Dto>> GetListAsync(GetTAX_2036ListInput input)
    {
        var queryable = await _repository.GetQueryableAsync();
        var filteredQuery = queryable
            .WhereIf(!string.IsNullOrWhiteSpace(input.CPlantId), storageLocation => storageLocation.CPlantId.Contains(input.CPlantId!))
            .WhereIf(!string.IsNullOrWhiteSpace(input.CStoreHouse), storageLocation => storageLocation.CStoreHouse.Contains(input.CStoreHouse!))
            .WhereIf(!string.IsNullOrWhiteSpace(input.CStoLocation), storageLocation => storageLocation.CStoLocation.Contains(input.CStoLocation!))
            .WhereIf(!string.IsNullOrWhiteSpace(input.CStoType), storageLocation => storageLocation.CStoType.Contains(input.CStoType!))
            .WhereIf(!string.IsNullOrWhiteSpace(input.CStoLocationTxt), storageLocation => storageLocation.CStoLocationTxt != null && storageLocation.CStoLocationTxt.Contains(input.CStoLocationTxt!));

        if (!input.IncludeInvalidData)
        {
            filteredQuery = filteredQuery.Where(storageLocation => storageLocation.CIsUse == "Y");
        }

        var query = filteredQuery
            .OrderBy(string.IsNullOrWhiteSpace(input.Sorting) ? nameof(TAX_2036.CStoLocation) : input.Sorting)
            .Skip(input.SkipCount)
            .Take(input.MaxResultCount);

        var storageLocations = await AsyncExecuter.ToListAsync(query);
        var totalCount = await AsyncExecuter.CountAsync(filteredQuery);

        return new PagedResultDto<TAX_2036Dto>(
            totalCount,
            ObjectMapper.Map<List<TAX_2036>, List<TAX_2036Dto>>(storageLocations)
        );
    }

    [Authorize(MmsNTPermissions.Mes.BasicData.TAX_2036.Create)]
    public async Task<TAX_2036Dto> CreateAsync(CreateUpdateTAX_2036Dto input)
    {
        var storageLocation = ObjectMapper.Map<CreateUpdateTAX_2036Dto, TAX_2036>(input);
        await _repository.InsertAsync(storageLocation);
        return ObjectMapper.Map<TAX_2036, TAX_2036Dto>(storageLocation);
    }

    [Authorize(MmsNTPermissions.Mes.BasicData.TAX_2036.Edit)]
    public async Task<TAX_2036Dto> UpdateAsync(int id, CreateUpdateTAX_2036Dto input)
    {
        var storageLocation = await _repository.GetAsync(id);
        ObjectMapper.Map(input, storageLocation);
        await _repository.UpdateAsync(storageLocation);
        return ObjectMapper.Map<TAX_2036, TAX_2036Dto>(storageLocation);
    }

    [Authorize(MmsNTPermissions.Mes.BasicData.TAX_2036.Delete)]
    public async Task DeleteAsync(int id)
    {
        await _repository.DeleteAsync(id);
    }
}

TAX_2036AutoMapperProfile.cs

c# 复制代码
using AutoMapper;
using Step.MmsNT.BasicData;

namespace Step.MmsNT.TAX_2036Service;

public class TAX_2036AutoMapperProfile : Profile
{
    public TAX_2036AutoMapperProfile()
    {
        CreateMap<TAX_2036, TAX_2036Dto>();
        CreateMap<CreateUpdateTAX_2036Dto, TAX_2036>();
    }
}

3.6 Step.MmsNT.Application.Contracts按钮权限

E:\MyProject\mms\mms_server\src\Step.MmsNT.Application.Contracts\Permissions\MmsNTPermissionDefinitionProvider.cs

MmsNTPermissionDefinitionProvider.cs

c# 复制代码
        var tax2036 = mesBasicData.AddChild(MmsNTPermissions.Mes.BasicData.TAX_2036.Default, L("Permission:TAX_2036"));
        tax2036.AddChild(MmsNTPermissions.Mes.BasicData.TAX_2036.Create, L("Permission:TAX_2036.Create"));
        tax2036.AddChild(MmsNTPermissions.Mes.BasicData.TAX_2036.Edit, L("Permission:TAX_2036.Edit"));
        tax2036.AddChild(MmsNTPermissions.Mes.BasicData.TAX_2036.Delete, L("Permission:TAX_2036.Delete"));

MmsNTPermissions.cs

c# 复制代码
public static class TAX_2036
{
    public const string Default = ModuleName + ".TAX_2036";
    public const string Create = Default + ".Create";
    public const string Edit = Default + ".Edit";
    public const string Delete = Default + ".Delete";
}

3.7 Step.MmsNT.Domain.Shared国际化多语言

E:\MyProject\mms\mms_server\src\Step.MmsNT.Domain.Shared\Localization\MmsNT\en.json

json 复制代码
"Permission:TAX_2036": "Storage Location Master Data",
"Permission:TAX_2036.Create": "Create Storage Location",
"Permission:TAX_2036.Edit": "Edit Storage Location",
"Permission:TAX_2036.Delete": "Delete Storage Location",

E:\MyProject\mms\mms_server\src\Step.MmsNT.Domain.Shared\Localization\MmsNT\zh-Hans.json

json 复制代码
"Permission:TAX_2036": "仓位基础数据维护",
"Permission:TAX_2036.Create": "创建仓位",
"Permission:TAX_2036.Edit": "编辑仓位",
"Permission:TAX_2036.Delete": "删除仓位",

四、项目展示

五、资源链接

相关推荐
电商API_180079052471 小时前
Python 实现闲鱼商品列表批量采集,接口异常重试机制搭建
大数据·开发语言·数据库·爬虫·python
DogDaoDao1 小时前
深入理解 Qt:从原理到实战的全景指南
开发语言·qt·程序员
放下华子我只抽RuiKe51 小时前
FastAPI 全栈后端(四):认证与授权
开发语言·前端·javascript·python·深度学习·react.js·fastapi
我是唐青枫2 小时前
Java Spring Data JPA 实战指南:Repository 查询、分页与实体映射
java·开发语言
张忠琳2 小时前
【Go 1.26.4】(Part 2) Go 1.26.4 超深度分析 — Runtime GMP 调度器 (proc.go + runtime2.go)
开发语言·golang
阿坤带你走近大数据2 小时前
java中泛型不能用基础数据类型
java·开发语言
weixin_307779132 小时前
从脚本执行到智能体协作:AI辅助测试能力的范式重构
运维·开发语言·人工智能·算法·测试用例
云絮.3 小时前
增删改查操作
java·开发语言
themingyi3 小时前
Abaqus2024安装python包pandas
开发语言·python·pandas