按照DDD的方式写的一个.net有关Web项目框架

news/2025/9/24 9:22:47/文章来源:https://www.cnblogs.com/mq0036/p/19108566

按照DDD的方式写的一个.net有关Web项目框架

理想很丰满,现实往往很残酷。

一种按照ddd的方式,根据业务来把自己需要的模块一个一个写出来,再按照模块把需要的接口一个一个的写出来,堆砌一些中间件,以及解耦的command,handler等等

,一个项目就这么成型了。上面的项目有一个非常清晰的特点,就是按需开发,不需要去可以定义业务相关的公共的模块,有就有没就没。这项目看起来没有什么公共框架,就是一个项目。当然这样效率性能也是最高的,不需要过多的包装一层又一层的公共代码。

有关示例如下,不做过多的赘述:

liuzhixin405/netcore-micro (github.com)

一种业务非常大,开发人员只需要写业务实现,这就需要一个公共框架,提供公共的可复制模块让业务人员写业务代码。

下面以为简洁的方式呈现这种开发模式,项目层级如下:

三个模块分别是业务模块,主机,基础模块。业务模块Business通过dll形式提供给host来完成注册和发布。

主机host可以存放公共的基础模块,例如注册、登录、认证等,这里省略。

业务模块存放业务代码,包括提供接口。

流程如下:request => 业务模块controller => business => service=> repository

整个项目接口不变,实现可各异。

 在仓储层定义几个公共的方法,

复制代码
 public interface IRepository<TEntity,TID> where TEntity : IEntity<TID>{Task<ApiResult> AddAsync(TEntity entity);Task<ApiResult> UpdateAsync(TEntity entity);Task<ApiResult> DeleteAsync(Expression<Func<TEntity, bool>> filter);Task<ApiResult> DeleteAsync(TID id);// 通用分页查询Task<PagedResult<TEntity>> GetPagedAsync(PagingParameters<TEntity> pagingParameters);// 其他常用操作Task<IEnumerable<TEntity>> FindAsync(Expression<Func<TEntity, bool>> filter);}
复制代码

服务层也是同样的方法

复制代码
 [Intercept("business-service log")]public interface IService{Task<ApiResult> AddAsync(IRequestDto requestDto);Task<ApiResult> UpdateAsync(IRequestDto requestDto);Task<ApiResult> DeleteAsyncc(IRequestDto requestDto);Task<ApiResult> GetPagedAsyncc(IRequestDto requestDto) ;Task<ApiResult> FindAsyncc(IRequestDto requestDto);}
复制代码

 

依赖注入还是老一套,实现它就行。

复制代码
 public interface IModule{void ConfigureService(IServiceCollection services, IConfiguration configuration = null);void Configure(IApplicationBuilder app, IWebHostEnvironment env = null);}public abstract class ModuleBase : IModule{public virtual void ConfigureService(IServiceCollection services, IConfiguration configuration = null){}public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env = null){}}
复制代码

在主机通过扫描assembly来注册服务

复制代码
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Project.Base.Reflect;
using System.Reflection;
using Project.Base.ProjExtension;
using Project.Base.Common;
using Project.Base.DependencyInjection;
using Project.Base.Module;
namespace Project.Host
{public class Program{public static void Main(string[] args){var builder = WebApplication.CreateBuilder(args);builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);builder.Configuration.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: true);builder.Configuration.AddJsonFile("appsettings.Modules.json", optional: false, reloadOnChange: true);//IModule注入 ,然后扫描调用ConfigureService,Business注入需要的服务入口
            builder.Services.InitModule(builder.Configuration);var sp = builder.Services.BuildServiceProvider();var moduleInitializers = sp.GetServices<IModule>();foreach (var moduleInitializer in moduleInitializers){moduleInitializer.ConfigureService(builder.Services, builder.Configuration);}// Add services to the container.var assemblys = GolbalConfiguration.Modules.Select(x => x.Assembly).ToList();var mvcBuilder=builder.Services.AddControllers().ConfigureApplicationPartManager(apm => {var folder = Path.Combine(Directory.GetCurrentDirectory(), "bus_lib");var serviceList = (builder.Configuration.GetSection("ServiceList").Get<string[]>()) ?? new string[] { "ADM" };//默认加载基础服务string[] serviceFiles = Directory.GetFiles(folder, "*.Api.dll").Where(x =>serviceList.Any(y => x.Contains(y))).ToArray();foreach (var file in serviceFiles){if (File.Exists(file)){var assembly = Assembly.LoadFrom(file);var controllerAssemblyPart = new AssemblyPart(assembly);apm.ApplicationParts.Add(controllerAssemblyPart);}}});foreach (var assembly in assemblys){// 扫描并注册其他程序集中的控制器
                mvcBuilder.AddApplicationPart(assembly);// 扫描并注册其他程序集中的服务   针对特性注入
                builder.Services.ReisterServiceFromAssembly(assembly);} // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            builder.Services.AddEndpointsApiExplorer();builder.Services.AddSwaggerGen();builder.Services.AddBusinessServices();var app = builder.Build();ServiceLocator.Instance = app.Services;//imodule 的Configure调用,business可以实现中间件等操作foreach (var moduleInitializer in moduleInitializers){moduleInitializer.Configure(app, app.Environment);}// Configure the HTTP request pipeline.if (app.Environment.IsDevelopment()){app.UseSwagger();app.UseSwaggerUI();}app.UseHttpsRedirection();app.UseAuthorization();app.MapControllers();app.Run();}}
}
复制代码

 

业务需求注入代码如下:

复制代码
using ADM001_User.Model;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Bson.Serialization;
using MongoDB.Bson;
using MongoDB.Driver;
using Project.Base.IRepository;
using Project.Base.Module;
using Project.Base.Reflect;
using Project.Base.Repository;
using Project.Base.Services;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ADM001_User.Business.Settings;
using Project.Base.Model;namespace ADM001_User.Business
{public class UserModule : ModuleBase{public override void ConfigureService(IServiceCollection services, IConfiguration configuration = null){services.AddDbContext<UserDbContext>(options =>options.UseInMemoryDatabase("InMemoryDb"));services.AddScoped<IRepository<User, int>, GenericRepository<User, int, UserDbContext>>();services.AddTransient<IService, UserService>();AddMongo(services);AddMongoRepository<User, int>(services, "users");}private static IServiceCollection AddMongo(IServiceCollection services){BsonSerializer.RegisterSerializer(new GuidSerializer(BsonType.String));BsonSerializer.RegisterSerializer(new DateTimeOffsetSerializer(BsonType.String));services.AddSingleton(serviceProvider =>{var configuration = serviceProvider.GetService<IConfiguration>();var serviceSettings = configuration.GetSection(nameof(ServiceSettings)).Get<ServiceSettings>();var mongoDbSettings = configuration.GetSection(nameof(MongoDbSettings)).Get<MongoDbSettings>();var mongoClient = new MongoClient(mongoDbSettings.ConenctionString);return mongoClient.GetDatabase(serviceSettings.ServiceName);});return services;}private static IServiceCollection AddMongoRepository<T, TID>(IServiceCollection services, string collectionName) where T : IEntity<TID>{services.AddSingleton<IRepository<User, int>>(serviceProvider =>{var db = serviceProvider.GetService<IMongoDatabase>();return new MongoRepository<User, int>(db, "collectionname");});return services;}}
}
复制代码

 

在business层加了aop,通过proxy的方式

复制代码
using Castle.DynamicProxy;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;namespace Project.Base.Reflect
{public static class ServiceExtension{private static readonly ProxyGenerator _generator = new ProxyGenerator();public static IServiceCollection AddBusinessServices(this IServiceCollection services){var folder = Path.Combine(Directory.GetCurrentDirectory(), "bus_lib");var dllFiles = Directory.GetFiles(folder, "*.Business.dll");var assemblies = dllFiles.Select(Assembly.LoadFrom).ToArray();var businessTypes = assemblies.SelectMany(a => a.GetTypes().Where(t => t.IsClass&&!t.IsAbstract)).Where(type => type.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IBusiness<>))).ToList();CastleInterceptor castleInterceptor = new CastleInterceptor();foreach (var type in businessTypes){var interfaceType = type.GetInterfaces().First(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IBusiness<>));services.AddTransient(interfaceType, provider =>{var target = ActivatorUtilities.CreateInstance(provider, type);return _generator.CreateInterfaceProxyWithTarget(interfaceType, target, castleInterceptor);});}return services;}}
}
复制代码

在你需要的每个方法前加上特性就可以了

复制代码
using Project.Base.Model;
using Project.Base.ProjAttribute;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace ADM001_User.Business
{/// <summary>/// 有需要就实现前后动作/// </summary>public class AddAop: BaseAopAttribute{public override Task After(BusinessAopContext aopContext){return Task.CompletedTask;}public override Task Before(BusinessAopContext aopContext){return Task.CompletedTask;}}
}
复制代码

 

再控制器层加了个公共的,不管是controller拦截还是公共的部分都可以写到这里

复制代码
 [Route("api/[controller]/[action]")][ApiController]public class InitController<TModel>:ControllerBase{protected readonly ILogger<InitController<TModel>> _logger;public InitController(ILogger<InitController<TModel>> logger){_logger = logger;}}
复制代码

 

该框架主打就是一个简陋,像日志,缓存 ,消息中间件都可以提前约定好公共接口,service层接口调用,business层注入需要的实现。按照接口和实现分离的方式该项目还需要调整下目录

地址如下:

liuzhixin405/single-arch (github.com)

 

2025-09-24 09:16:50【出处】:https://www.cnblogs.com/morec/p/18276172

=======================================================================================

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/915484.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

css-图片文字对齐方式

<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">&…

基于Python+Vue开发的摄影网上预约管理系统源码+运行步骤

项目简介该项目是基于Python+Vue开发的摄影网上预约管理系统(前后端分离),影楼婚纱摄影,这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能,同时锻炼他们的项目设计与开发…

【习题答案】《深入理解计算机系统(原书第三版)》

第一章 计算机系统漫游考察Amdahl 定律【练习题 1.1】 假设你是个卡车司机,要将土豆从爱达荷州的 Boise 运送到明尼苏达州的 Minneapolis, 全程 2500 公里。在限速范围内,你估计平均速度为 100 公里/小时,整个行程需…

企业网站推广方案网络营销作业seo技巧与技术

引言 一、性能怪兽-Nginx概念深入浅出 二、Nginx环境搭建 三、Nginx反向代理-负载均衡 四、Nginx动静分离 五、Nginx资源压缩 六、Nginx缓冲区 七、Nginx缓存机制 八、Nginx实现IP黑白名单 九、Nginx跨域配置 十、Nginx防盗链设计 十一、Nginx大文件传输配置 十二、Nginx配置SL…

建设网站公司价格怎么查找一个网站开发时间

在Linux上安装Oracle时&#xff0c;经常会报以下错误&#xff1a;无法使用命令 /usr/X11R6/bin/xdpyinfo 自动检查显示器颜色。请检查是否设置了DISPLA在Linux上安装Oracle时&#xff0c;经常会报以下错误&#xff1a;无法使用命令 /usr/X11R6/bin/xdpyinfo 自动检查显示器颜色…

用什么手机软件做网站成都创软科技的口碑

找问题找了一个多小时&#xff0c;不停调试&#xff0c;还修改文件路径&#xff0c;配置路径&#xff0c;开机关机&#xff0c;最后终于做出来了&#xff0c;得出来了一个结论 我绝对是天才 首先 看这个视频 k14 打包发布_哔哩哔哩_bilibili 不出意外&#xff0c;你绝对会在…

什么公司时候做网站佛山科技网站建设

飞书如何修改名称 点击编辑信息 在这里修改姓名就可以啦

google doc wordpressseo门户网站

来源&#xff5c;Sophia知乎&#xff0c;https://zhuanlan.zhihu.com/p/152362317本文仅用于学术分享&#xff0c;如有侵权&#xff0c;联系后台作删文处理编译&#xff1a;极市平台最近在做笔记查阅内容&#xff0c;觉得这个总结太美观了&#xff0c;真是棒&#xff01;吴恩达…

网站开发费用摊销时间互联网seo是什么

作者 | 小碗汤来源 | 我的小碗汤今天分享一个可以图形化搭建k8s集群的项目&#xff0c;不妨试一试~本项目是基于 Kubespray 提供图形化的 K8S 集群离线安装、维护工具。Kubespray&#xff1a;https://github.com/kubernetes-sigs/kubesprayKuboard-SprayKuboard-Spray 是一款可…

css-文字溢出省略号显示

<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">&…

天津网站制作专业深圳营销型网站制作

什么叫PC和手机端URL途径规范性在网址百度搜索引擎提升的全过程中&#xff0c;会牵涉到途径方位的难题。网址中的同一个网页页面只相匹配一个网站地址。一个规范化和简易的网站地址有利于检索和捕捉客户的记忆力&#xff0c;回绝好几条途径&#xff0c;偏向同一个网页页面&…

深入解析:mosquitto求医之路(3):Docker安装也不好使

深入解析:mosquitto求医之路(3):Docker安装也不好使pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&…

软件体系结构——负载均衡 - 指南

软件体系结构——负载均衡 - 指南2025-09-24 09:16 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !impor…

css-定位让盒子居中显示

<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">&…

Qwen3-Max 2025年完整发布解析:阿里巴巴最强AI模型深度评测

Qwen3-Max 2025年完整发布解析:阿里巴巴最强AI模型深度评测Qwen3-Max 是阿里巴巴推出的迄今为止规模最大、能力最强的大语言模型。作为 Qwen3 系列的旗舰产品,该模型在2025年1月正式发布,标志着中国AI技术在全球竞争…

地域购物网站wordpress 回复显示不出来

目录 1. 有效的括号 思路&#xff1a; 2.用队列实现栈 思路&#xff1a; 3.用栈实现队列 思路&#xff1a; 4.设计循环队列 思路&#xff1a; 1. 有效的括号 20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09; 给定一个只包括 (&#xff0c;)&#xff0c;{&…

运城做网站电话网页设计实验报告分析

【物联网阿里云平台开发项目实战|附课件资料】智能硬件开发-数据上云&#xff0c;零基础入门 4G模块连接阿里云教程 MQTT通信协议(mosquitto)在Linux上的环境构建与测试 MQTT通信协议(mosquitto)发布订阅例子C语言实现 MQTT客户端软件(MQTT.fx)的使用详解 各类MQTT代理服务器特…

企业网站建设公司网络服务上海知名的网站建设

这是今天和校招新同事交流时的总结&#xff0c;希望校招新同事能够回顾&#xff0c;也能够写出自己的总结。 一、什么是代码高手&#xff1f;你怎么证明自己是代码高手&#xff1f; 知道许多代码技巧、JS炫彩技巧的人大有人在。你知道多少个.net函数&#xff0c;这一点都没有意…

国外家居设计网站客户管理系统免费

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于Spring,SpringMVC,MyBatis的高校大…