• NLayerAppV3--.net Core2实现的DDD分层架构


            虽然每天的工作都是CURD、还是使用着传统的三层架构、使用着.net Framework,但是这并不能影响我学习DDD和.net core。

    总是希望软件在应对复杂多变的场景时能够游刃有余,在解决问题时能够多一种选择。

            很早就有关注大神dax.netNLayerApp系列博文https://www.cnblogs.com/daxnet/category/304141.html

            近期入坑.net core,看了进击的辣条的文章Asp.Net Core微服务初体验,很有收获,感谢感谢。

            抽时间读了下NLayerAppV3项目的源码,Github地址:https://github.com/cesarcastrocuba/nlayerappv3

    分享下体会,希望相互交流学习,谢谢!

    1、项目简介

    NLayerAppV3是一个使用.net 2.1实现的经典DDD的分层架构的项目。

    NLayerAppV3是在NLayerAppV2的基础上,使用.net core2.1进行重新构建的;它包含了开发人员和架构师都可以重用的DDD层;以银行和博客上下文示例。

    2、项目结构

    放一张DDD风格架构l图。主要分为四层:表现层、应用层、领域层和基础结构层。

    详细的各层的含义可以查看dax.net的文章https://www.cnblogs.com/daxnet/archive/2011/05/10/2042095.html

    1.1-Presentation(表现层)

    系统和用户的交互层。UI展示给终端用户、收集用户的反馈信息。

    1.2-Distributed Services(分布式服务层)

    为应用程序提供远程访问;如果是http协议,一般设计为WebApi。

    1.2.1-Seedwork --DistributedServices.Seedwork

    分布式服务的Controller、Filter等

    1.2.2-MainBoundedContext

    --DistributedServices.MainBoundedContext

    以银行的业务示例,构建上下文、对外提供WebApi服务,结合Swagger UI

    --DistributedServices.MainBoundedContext.Tests

    DistributedServices.MainBoundedContext的测试项目

    1.2.3-BlogContext

    --DistributedServices.BlogBoundedContext

    以博客业务示例,构建上下文,对外提供WebApi服务,结合Swagger UI

    --DistributedServices.BlogBoundedContext.Tests

    DistributedServices.BlogBoundedContext项目的测试项目

    1.3-Application(应用层)

    协调领域模型与其它应用、包括事务调度、UOW、数据转换等。

    主要作用:通过仓储来访问持久层;对不同领域的数据组织整理;协调领域对象之间、领域对象与基础层的协作关系;应用服务等

    1.3.1-Seedwork --Application.Seedwork

    应用层共用接口、实现的封装

    1.3.2-MainBoundedContext

    --Application.MainBoundedContext

    业务模块的应用层服务接口和实现

    --Application.MainBoundedContext.DTO

    应用层业务模块的数据转换等

    --Application.MainBoundedContext.Tests

    Application.MainBoundedContext的测试项目

    1.3.3-BlogBoundedContext

    同1.3.2,不同的是业务换为博客业务

    1.4-Domain(领域层)

    展现业务/领域逻辑、业务处理状态,以及实现业务规则,它同时也包含了领域对象的状态信息。

    1.4.1-Seedwork

    --Domain.Seedwork

    领域层实体基类、仓储接口、UOW接口、值对象基类、规约等

    --Domain.Seedwork.Tests

    Domain.Seedwork的测试项目

    1.4.2-MainBoundedContext

    --Domain.MainBoundedContext

    实体、值对象、领域服务、聚合根、聚合及工厂

    --Domain.MainBoundedContext.Tests

    Domain.MainBoundedContext的测试项目

    1.4.3-BlogBoundedContext

    同1.4.2 业务逻辑换成了博客

    1.5-Infrastructure(基础设施层)

    1.5.1-Data  

    为应用程序的数据存取提供服务,它可以是应用程序本身的持久化机制,也可以是外部系统提供的数据访问的Web Service等

    --Infrastructure.Data.Seedwork

    UOW的实现基类、仓储的实现基类

    --Infrastructure.Data.MainBoundedContext

    UOW的实现、仓储的实现

    --Infrastructure.Data.MainBoundedContext.Tests

    Infrastructure.Data.MainBoundedContext的测试项目

    1.5.2-CrossCutting 

    该层提供了能被其它各层访问的通用技术框架,比如异常捕获与处理、日志、认证、授权、验证、跟踪、监视、缓存等等。

    --Infrastructure.Crosscutting

    适配器、国际化、验证等接口的封装

    --Infrastructure.Crosscutting.NetFramework

    适配器、国际化、验证等实现、国际化依赖的资源

    --Infrastructure.Crosscutting.Tests

    Infrastructure.Crosscutting的测试项目

    3、示例

    以DistributedServices.MainBoundedContext项目的BankAccounts的转账api示例,说明下我的理解

    [HttpPut]
            public void PerformTransfer([FromBody]BankAccountDTO from, [FromBody]BankAccountDTO to, [FromBody]decimal amount)
            {
                _bankAppService.PerformBankTransfer(from, to, amount);
            }
    View Code

    _bankAppService通过构造函数注入。

    readonly IBankAppService _bankAppService;
    
            public BankAccounts(IBankAppService bankAppService)
            {
                _bankAppService = bankAppService;
            }
    View Code

    IBankAppService是应用层的服务接口

    对应的应用层有接口的实现BankAppService

    public BankAppService(IBankAccountRepository bankAccountRepository, // the bank account repository dependency
                                  ICustomerRepository customerRepository, // the customer repository dependency
                                  IBankTransferService transferService,
                                  ILogger<BankAppService> logger)
            {
                //check preconditions
                if (bankAccountRepository == null)
                    throw new ArgumentNullException("bankAccountRepository");
    
                if (customerRepository == null)
                    throw new ArgumentNullException("customerRepository");
    
                if (transferService == null)
                    throw new ArgumentNullException("trasferService");
    
                _bankAccountRepository = bankAccountRepository;
                _customerRepository = customerRepository;
                _transferService = transferService;
    
                _logger = logger;
                _resources = LocalizationFactory.CreateLocalResources();
    
            }
    View Code

    BankAppService通过构造函数注入了领域层的银行账号仓储IBankAccountRepository和客户仓储ICustomerRepository、转账服务等,全部依赖于接口。

    public void PerformBankTransfer(BankAccountDTO fromAccount, BankAccountDTO toAccount, decimal amount)
            {
                //Application-Logic Process: 
                // 1º Get Accounts objects from Repositories
                // 2º Start Transaction
                // 3º Call PerformTransfer method in Domain Service
                // 4º If no exceptions, commit the unit of work and complete transaction
    
                if (BankAccountHasIdentity(fromAccount)
                    &&
                    BankAccountHasIdentity(toAccount))
                {
                    var source = _bankAccountRepository.Get(fromAccount.Id);
                    var target = _bankAccountRepository.Get(toAccount.Id);
    
                    if (source != null & target != null) // if all accounts exist
                    {
                        using (TransactionScope scope = new TransactionScope())
                        {
                            //perform transfer
                            _transferService.PerformTransfer(amount, source, target);
    
                            //comit unit of work
                            _bankAccountRepository.UnitOfWork.Commit();
    
                            //complete transaction
                            scope.Complete();
                        }
                    }
                    else
                        _logger.LogError(_resources.GetStringResource(LocalizationKeys.Application.error_CannotPerformTransferInvalidAccounts));
                }
                else
                    _logger.LogError(_resources.GetStringResource(LocalizationKeys.Application.error_CannotPerformTransferInvalidAccounts));
    
            }
    View Code

    实现转账的功能,输入参数都是Dto对象,通过AutoMapper或者其它映射工具完成数据转换;通过仓储访问聚合,获取源和目标账号信息、开启事务,UOW提交转账操作。

    DistributedServices.MainBoundedContext的StartUp中注册IOC

    仓储、领域服务、应用层服务、适配器、国际化、验证、Swagger UI等。

    运行项目

    在DistributedServices.MainBoundedContext目录下打开cmd命令,输入dotnet restore,完成之后,输入dotnet run

    运行结果:

     4、想法和计划

    跟.net core microservice结合

    使用ocelot搭建服务网关、结合identityserver4实现授权认证;polly服务熔断;限流;consul服务发现;Appolo配置中心;Skywalking追踪结果。

  • 相关阅读:
    webbrowser获取页面文章指定段落内容
    webbrowser防止弹窗(IE)
    webbrowser模拟手动输入
    WPF加载Winform窗体时 报错:子控件不能为顶级窗体
    FAQs: 我们可以在那里来为我的没有提升管理权限的应用程序存储用户数据?
    Winform中修改WebBrowser控件User-Agent的方法(已经测试成功)
    必应代码搜索 Bing Code Search 安装
    Microsoft Visual Studio Professional 2012 专业版 下载
    vs2012 aspx 没有设计视图了?
    vs2010 Express 下载连接
  • 原文地址:https://www.cnblogs.com/net-yuan/p/NLayerAppV3.html
Copyright © 2020-2023  润新知