推荐 .NET 8.0 开源项目伪微服务框架
<h2 data-tool="mdnice编辑器"><span class="prefix"><span class="content">前言</span></span></h2><p data-tool="mdnice编辑器">嘿,小伙伴们!最近看到了一个 .NET 8.0 的小项目伪微服务框架,非常适合想要快速搭建小型应用项目或是想要学习.NET 8.0及新的技术,但又不知道从哪里学起的朋友。这个框架可以帮助我们简化开发流程,同时还能适应不断变化的需求。</p>
<p data-tool="mdnice编辑器">它虽然简化了很多复杂的微服务特性,但仍保留了关键的微服务理念,让我们可以专注于业务逻辑而不是底层细节,并且达到实操效果。</p>
<p data-tool="mdnice编辑器">想要快速上手 .NET 8.0,不妨试试这个框架。项目已经在 GitHub 上开源了,欢迎大家前来围观、提供建议或贡献代码。希望这个框架能够帮助更好的帮助我们工作中遇到的问题。</p>
<h2 data-tool="mdnice编辑器"><span class="prefix"><span class="content">项目介绍</span></span></h2>
<p data-tool="mdnice编辑器">为什么说是伪微服务框架,常见微服务框架可能还包括服务容错、服务间的通信、服务追踪和监控、服务注册和发现等等,而这里为了在使用中的更简单,将很多东西进行了简化或者省略了。</p>
<p data-tool="mdnice编辑器"><strong>简化微服务概念</strong>:作者虽然称为“伪微服务”,但本框架依然具备一些关键的微服务特性,如模块化设计和服务解耦。它通过减少复杂的服务间通信、容错机制和服务发现等功能,使开发更加高效且易于管理。</p>
<p data-tool="mdnice编辑器"><strong>技术栈</strong>:集成了一些比较实用的新技术,包括EF Core、Redis、RabbitMQ和MySQL,确保应用高效又能应对高并发场景。</p>
<p data-tool="mdnice编辑器"><strong>易用性</strong>:该框架的目标是尽可能地简化开发过程,提供完整的接口和文档,能够迅速上手,并将更多精力集中在业务逻辑上。</p>
<p data-tool="mdnice编辑器"><strong>持续优化</strong>:尽管目前仍处于早期阶段,但作者承诺将持续改进和完善该项目。这包括但不限于引入更多高级特性、增强现有功能以及提升整体性能。</p>
<h2 data-tool="mdnice编辑器"><span class="prefix"><span class="content">项目核心</span></span></h2>
<p data-tool="mdnice编辑器"><strong>对象映射</strong>:使用 <code>AutoMapper</code> 自动处理对象之间的映射,让你无需手动编写繁琐的转换代码。</p>
<p data-tool="mdnice编辑器"><strong>查询封装</strong>:通过 <code>Ardalis.Specification</code> 和 <code>LinqKit.Core</code> 封装 EF Core 查询,让数据获取变得更简单直观。</p>
<p data-tool="mdnice编辑器"><strong>数据库交互</strong>:在 EF Core 中重写了 <code>SaveChangesInterceptor</code>,实现了软删除功能,并自动管理创建时间和更新时间字段。</p>
<p data-tool="mdnice编辑器"><strong>整体架构</strong>:采用了整洁的架构设计,便于理解和维护。</p>
<p data-tool="mdnice编辑器"><strong>业务功能</strong>:已经预置了一些基本的业务功能,开箱即用。</p>
<p data-tool="mdnice编辑器"><strong>依赖注入</strong>:内置了依赖注入容器,方便管理组件和服务。</p>
<p data-tool="mdnice编辑器"><strong>认证与授权</strong>:使用双 token 实现了安全登录和无感知的前端 token 刷新。</p>
<p data-tool="mdnice编辑器"><strong>分布式 ID 生成</strong>:集成了 <code>Snowflake</code> 分布式 ID 生成器,确保全局唯一标识符。</p>
<p data-tool="mdnice编辑器"><strong>缓存与锁</strong>:通过 Redis 实现了分布式缓存和分布式锁,提高了系统的可用性和并发性能。</p>
<p data-tool="mdnice编辑器"><strong>消息队列</strong>:利用 <code>RabbitMQ</code> 封装了异步任务处理机制,如文件上传和下载。</p>
<p data-tool="mdnice编辑器"><strong>定时任务</strong>:结合 <code>Cronos</code> 和 <code>BackgroundService</code> 实现了秒级定时任务。</p>
<p data-tool="mdnice编辑器"><strong>数据初始化</strong>:使用 <code>BackgroundService</code> 进行数据初始化,比如字典数据的加载。</p>
<p data-tool="mdnice编辑器"><strong>日志记录</strong>:采用 <code>Serilog</code> 记录异常日志,并通过 Docker 部署实现日志的可视化监控。</p>
<p data-tool="mdnice编辑器"><strong>操作日志</strong>:通过自定义过滤器和反射记录操作日志,便于追踪用户行为。</p>
<p data-tool="mdnice编辑器"><strong>权限验证</strong>:实现了权限验证过滤器,确保用户只能访问被授权的资源。</p>
<p data-tool="mdnice编辑器"><strong>统一响应格式</strong>:使用 <code>IAsyncResultFilter</code> 统一了返回给前端的数据格式。</p>
<p data-tool="mdnice编辑器"><strong>Excel 操作</strong>:集成 <code>EPPlus</code> 库,支持 Excel 导入和导出。</p>
<p data-tool="mdnice编辑器"><strong>一键部署</strong>:支持使用 <code>goploy</code> 快速部署前后端应用。</p>
<p data-tool="mdnice编辑器"><strong>API 文档</strong>:通过 <code>Swagger</code> 自动生成 RESTful API 文档,方便前端和后端开发人员协作。</p>
<p data-tool="mdnice编辑器"><strong>配置加载</strong>:自动加载 <code>appsettings.json</code> 文件中的配置信息。</p>
<h2 data-tool="mdnice编辑器"><span class="prefix"><span class="content">项目框架</span></span></h2>
<p data-tool="mdnice编辑器">通过Github下载项目源码,我们可以查看项目框架,具体如下图所示:</p>
<p><img src="https://img2024.cnblogs.com/blog/576536/202408/576536-20240823165609019-1106450563.png" width="619" height="700" loading="lazy" style="vertical-align: middle; display: block; margin-left: auto; margin-right: auto"></p>
<img alt="">
<p data-tool="mdnice编辑器">1、Libraries</p>
<p data-tool="mdnice编辑器">包含各种外部类库,对其深加工使用在项目中</p>
<p data-tool="mdnice编辑器">2、Services/Basic</p>
<p data-tool="mdnice编辑器">微服务基础支撑子系统</p>
<p data-tool="mdnice编辑器">3、Services/NCDP</p>
<p data-tool="mdnice编辑器">微服务业务子系统</p>
<p data-tool="mdnice编辑器">4、Services/SystemService</p>
<p data-tool="mdnice编辑器">微服务系统服务(包括数据库的更新、定时任务、数据初始化、Swagger承载、RabbitMQ队列事件处理器等)</p>
<p data-tool="mdnice编辑器">5、sun.Core</p>
<p data-tool="mdnice编辑器">sun.Core作为了中转,其他外部或者自己封装的类库,在引用的时候都是在sun.Core中进行的引用。</p>
<p data-tool="mdnice编辑器">算是间接引用,来简化项目中的依赖关系。</p>
<p data-tool="mdnice编辑器">同时在sun.Core也封装了一些核心组件和服务。</p>
<p><img src="https://img2024.cnblogs.com/blog/576536/202408/576536-20240823165855661-1876970856.png" alt="" loading="lazy" style="display: block; margin-left: auto; margin-right: auto"></p>
<p data-tool="mdnice编辑器">6、sun.Infrastructure</p>
<p data-tool="mdnice编辑器">主要封装一些通用的方法,以及基础设施组件,供外部使用。</p>
<p><img src="https://img2024.cnblogs.com/blog/576536/202408/576536-20240823165907878-476029284.png" alt="" loading="lazy" style="display: block; margin-left: auto; margin-right: auto"></p>
<h2 data-tool="mdnice编辑器"><span class="prefix"><span class="content">项目说明</span></span></h2>
<p data-tool="mdnice编辑器">关于项目详细使用情况可以查看作者整理的文章链接 https://www.cnblogs.com/aehyok/p/18058032 ,希望能够帮助大家更好的理解项目和学习知识点,提升自己的技术能力,下面只展示了部分内容。</p>
<h4 data-tool="mdnice编辑器"><span class="prefix"><span class="content">1、业务功能</span></span></h4>
<p data-tool="mdnice编辑器">目前基本实现的功能包括:用户管理、角色管理、区域管理、查看日志(登录日志和操作日志)、菜单管理、权限控制、系统管理等功能。</p>
<p><img src="https://img2024.cnblogs.com/blog/576536/202408/576536-20240823165950242-344963990.png" width="690" height="380" loading="lazy" style="vertical-align: middle; display: block; margin-left: auto; margin-right: auto"></p>
<h4 data-tool="mdnice编辑器"><span class="prefix"><span class="content">2、生成文档工具</span></span></h4>
<p data-tool="mdnice编辑器">Swagger 生成REST APIs文档工具包含可以承载多个微服务项目,通过右上角进行切换,便可以查看当前微服务项目的接口文档,并可以进行测试</p>
<p data-tool="mdnice编辑器">测试接口直接可在swagger ui上进行</p>
<p data-tool="mdnice编辑器">统一添加接口中的Header参数</p>
<p data-tool="mdnice编辑器">通过对Swagger UI进行部分的自定义,使的更好的适配自己的项目,比如添加登录,这样接口便直接可以在swagger UI上面进行。</p>
<p><img src="https://img2024.cnblogs.com/blog/576536/202408/576536-20240823170029758-1450910516.png" width="619" loading="lazy" style="vertical-align: middle; display: block; margin-left: auto; margin-right: auto"></p>
<h4 data-tool="mdnice编辑器"><span class="prefix"><span class="content">3、分布式雪花Id生成器</span></span></h4>
<p data-tool="mdnice编辑器">Snowflake 所使用的开源类库:https://github.com/stulzq/snowflake-net</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 分布式雪花Id生成器
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> SnowFlake
{
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 通过静态类只实例化一次IdWorker 否则生成的Id会有重复
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">readonly</span> Lazy<IdWorker> _instance = <span style="color: rgba(0, 0, 255, 1)">new</span>(() =><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> commonOptions = App.Options<CommonOptions><span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> IdWorker(commonOptions.WorkerId, commonOptions.DatacenterId);
});
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> IdWorker Instance =<span style="color: rgba(0, 0, 0, 1)"> _instance.Value;
}</span></pre>
</div>
<p data-tool="mdnice编辑器">其中 WorkerId和DatacenterId保持不同的话,例如两个微服务WorkerId一个为1一个为2,那么在同一毫秒数生成的Id肯定是不同的。</p>
<p data-tool="mdnice编辑器">同一个IdWorker在一个毫秒中可以生成4096个序列号 足够大型系统使用了,不怕重复的问题。</p>
<h4 data-tool="mdnice编辑器"><span class="prefix"><span class="content">4、分布式缓存和分布式锁</span></span></h4>
<p data-tool="mdnice编辑器">Redis 统一封装实现分布式缓存和分布式锁,所使用的开源类库:https://github.com/2881099/csredis</p>
<p data-tool="mdnice编辑器">目前主要封装了几个常用的接口方法</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> IRedisService
{
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 查看服务是否运行
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><returns></returns></span>
<span style="color: rgba(0, 0, 255, 1)">bool</span><span style="color: rgba(0, 0, 0, 1)"> PingAsync();
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 根据key获取缓存
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><param name="key"></param></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><returns></returns></span>
Task<T> GetAsync<T>(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> key);
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 设置指定key的缓存值(不过期)
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><param name="key"></param></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><param name="value"></param></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><returns></returns></span>
Task<<span style="color: rgba(0, 0, 255, 1)">bool</span>> SetAsync(<span style="color: rgba(0, 0, 255, 1)">string</span> key, <span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)"> value);
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 设置指定key的缓存值(可设置过期时间和Nx、Xx)
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><param name="key"></param></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><param name="value"></param></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><param name="expire"></param></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><param name="exists"></param></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><returns></returns></span>
Task<<span style="color: rgba(0, 0, 255, 1)">bool</span>> SetAsync(<span style="color: rgba(0, 0, 255, 1)">string</span> key, <span style="color: rgba(0, 0, 255, 1)">object</span> value, TimeSpan expire, RedisExistence? exists = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 设置指定key的缓存值(可设置过期秒数和Nx、Xx)
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><param name="key"></param></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><param name="value"></param></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><param name="expireSeconds"></span><span style="color: rgba(0, 128, 0, 1)">过期时间单位为秒</span><span style="color: rgba(128, 128, 128, 1)"></param></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><param name="exists"></param></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><returns></returns></span>
Task<<span style="color: rgba(0, 0, 255, 1)">bool</span>> SetAsync(<span style="color: rgba(0, 0, 255, 1)">string</span> key, <span style="color: rgba(0, 0, 255, 1)">object</span> value, <span style="color: rgba(0, 0, 255, 1)">int</span> expireSeconds = -<span style="color: rgba(128, 0, 128, 1)">1</span>, RedisExistence? exists = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 删除Key
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><param name="key"></param></span>
<span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><returns></returns></span>
Task<<span style="color: rgba(0, 0, 255, 1)">long</span>> DeleteAsync(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> key);
Task</span><Dictionary<<span style="color: rgba(0, 0, 255, 1)">string</span>,<span style="color: rgba(0, 0, 255, 1)">string</span>>><span style="color: rgba(0, 0, 0, 1)"> ScanAsync();
}</span></pre>
</div>
<p data-tool="mdnice编辑器">主要是为了保持与redis cli中的方法一致,选了这个类库,当然你也可以选择其他的类库 还是蛮多的。</p>
<p data-tool="mdnice编辑器">同时还封装了一个接口用于前端监测所有的key和value。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">async</span> Task<<span style="color: rgba(0, 0, 255, 1)">dynamic</span>><span style="color: rgba(0, 0, 0, 1)"> ScanAsync(PagedQueryModelBase model)
{
List</span><<span style="color: rgba(0, 0, 255, 1)">string</span>> list = <span style="color: rgba(0, 0, 255, 1)">new</span> List<<span style="color: rgba(0, 0, 255, 1)">string</span>><span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">根沐model.Keyword进行模糊匹配</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> scanResult = <span style="color: rgba(0, 0, 255, 1)">await</span> RedisHelper.ScanAsync(model.Page, $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">*{model.Keyword}*</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, model.Limit);
list.AddRange(scanResult.Items);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> values = <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> RedisHelper.MGetAsync(list.ToArray());
</span><span style="color: rgba(0, 0, 255, 1)">var</span> resultDictionary = list.Zip(values, (key, value) => <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> { key, value })
.ToDictionary(item </span>=> item.key, item =><span style="color: rgba(0, 0, 0, 1)"> item.value);
</span><span style="color: rgba(0, 0, 255, 1)">dynamic</span> result = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ExpandoObject();
result.Items </span>=<span style="color: rgba(0, 0, 0, 1)"> resultDictionary;
result.Cursor </span>= scanResult.Cursor;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 下一次要通过这个Cursor获取下一页的keys</span>
<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result;
}</span></pre>
</div>
<h4 data-tool="mdnice编辑器"><span class="prefix"><span class="content">5、自动化部署</span></span></h4>
<p data-tool="mdnice编辑器">通过google/zx使用nodejs开发了一个脚本,用于自动化部署</p>
<p data-tool="mdnice编辑器">可以参考Github的地址:https://github.com/aehyok/zx-deploy</p>
<p data-tool="mdnice编辑器">主要是用于开发环境,通过</p>
<div class="cnblogs_code">
<pre>pnpm sun-<span style="color: rgba(0, 0, 0, 1)">baisc
pnpm sun</span>-<span style="color: rgba(0, 0, 0, 1)">ncdp
pnpm sun</span>-systemserivce</pre>
</div>
<p data-tool="mdnice编辑器">当然你还可以通过组合命令进行部署,例如想一起部署三个服务</p>
<div class="cnblogs_code">
<pre>pnpm sun-all</pre>
</div>
<pre class="custom" data-tool="mdnice编辑器"><code class="hljs">其实就是 <br></code></pre>
<div class="cnblogs_code">
<pre><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">pnpm sun-ncdp && </span>
pnpm sun-basic &&<span style="color: rgba(0, 0, 0, 1)">
pnpm sun</span>-systemservice<span style="color: rgba(128, 0, 0, 1)">"</span></pre>
</div>
<p data-tool="mdnice编辑器">这里我用的<code>&&</code>相当于上面三个命令串行执行,先执行sun-ncdp,再执行sun-basic,最后执行sun-systemservice。</p>
<p data-tool="mdnice编辑器">如果你的电脑或者服务器性能足够好,可以使用<code>&</code>符号,这样就是并行执行,三个服务同时启动,这样可以节省时间。</p>
<p data-tool="mdnice编辑器">以上仅展示了项目的部分内容,还有许多其他的技术应用和功能需要大家去发现。</p>
<p data-tool="mdnice编辑器">然后我们可以下载源码参考文档并进行实际操作,以便全面了解整个项目的技术应用和特性。</p>
<h2 data-tool="mdnice编辑器"><span class="prefix"><span class="content">项目地址</span></span></h2>
<p data-tool="mdnice编辑器">Github:https://github.com/aehyok/.NET8.0</p>
<h2 class="md-end-block md-heading"><span class="md-plain">最后</span></h2>
<p><span class="md-plain"><span class="md-plain md-expand">如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。也可以加入微信公众号 <span class="md-pair-s "><strong></strong><span class="md-plain md-expand"> 社区,与其他热爱技术的同行一起交流心得,共同成长!</span></span></span></span></p>
<p><span class="md-plain"><img src="https://img2024.cnblogs.com/blog/576536/202408/576536-20240813102419584-1596250541.png" alt="" style="display: block; margin-left: auto; margin-right: auto"></span></p><br><br>
来源:https://www.cnblogs.com/1312mn/p/18376570
頁:
[1]