• DDD .NET Core 定义结构+依赖注入


    工作有些年头了一直在搬砖,下定决心从零开始写一套领域模型的项目

    把知道的东西变成会的,把会的东西融会贯通

    最终能不能用无所谓,总要留点什么东西

    Github 仓库地址

    每一篇文章对应一个 tag

    这版代码定义了

      领域模型中需要那些层

      层与层之间的基本引用

      使用.NET Core 内置的依赖注入框架,对各层之间进行解耦 (后面会替换成 Autofac)

    以下内容都只是我本人的理解,可能对也可能不对

    由于项目之间只引用了接口没有引用实现,所以直接编译后的DLL只有接口没有实现

    因此:

      一、各层编译后的DLL,都输出到同一个目录下

      二、Web项目,编译的时候把该项目中所有的DLL复制到 bin 文件中对应的路径下

    项目结构

    0-Infrastructure

      Core2022.Enum

      Core2022.Framework.Commons    定义一些公共方法

      Core2022.Framework    定义Domaim、Repository、UnitOfWork 基本实现,IoC、Middleware等实现

    1-Presentation  

      Core2022.API 

      Core2022.Web 

    2-Application

      Core2022.Application.Services

      Core2022.Application.Services.DTO    表现层与应用层之间交互用的对象

      Core2022.Application.Services.Interface 

    3-Domain

      Core2022.Domain

      Core2022.Domain.Model    ORM对象

      Core2022.Domain.Interface

    4-Repository

      Core2022.Repository

      Core2022.Repository.Interface

    概念:

    表现层:负责向用户显示或者收集用户输入的指令。(Web、API、WCF 等)

    应用层:对应一个具体的业务,指挥领域对象来解决问题。

    领域层:负责具体的业务概念、状态、规则等信息。

    基础设施层:为各层提供支持,为表现层提供中间件等、为应用层提供信息的传递、为领域层提供数据的持久化

    仓储层:某个领域独有的方法(获取修改数据的方法),放到该领域的仓储层中。

    领域对象与ORM对象

    ORM对象,只是一个用来和数据库表字段映射用的类型,他只能包含一些简单的属性(姓名、年龄等)

    领域对象,ORM对象只是领域对象的一个属性(私有属性),领域对象通过 Get,Set方法访问或者修改ORM对象。

            GetName() { return ORM对象.Name }

            SetName(string name) { ORM对象.Name = name }

            领域对象还包含其他属性(所在部门、直属领导)。

            UserDomain.GetDept() { return DeptDomain } 获取员工所在的部门

            UserDomain.GetLeader() { return UserDomain } 获取员工的直属领导

            UserDomain.GetCustome(Guid userKeyId)  { return List<CustomerDoamin> } 获取该员工的客户列表

         领域对象还包含了对象的行为、规则(发送消息)。

            UserDomain.SendInformation(string msg) { ... } 发送消息行为

            UserDomain.AddCustome(xxx) { 员工增加100块收入,部门任务整体奖金增加 } 增加客户规则

    在快速开发的时候,往往为了效率经常是怎么简单怎么来。因此业务逻辑会分散到表现层,应用层,数据层,数据库脚本,导致的后果就是后续分析问题的时候异常的困难。

    领域模型的高内聚、合理的分层可以解决这些问题。

    但是领域模型也有他自己的问题

      --select * from

      UPDATE t1 set t1.UserName = 'XXXX' from
     
     [user] as t1
      inner join Dept as t2 on t1.KeyId = t2.UserKeyId
      where t1.KeyId = 'F4095679-83B6-4646-9BFA-7745D7CD3AD0'

      比如我要修改某个员工他所在部门的名字,一条SQL就能完成,但是在领域模型中需要先来个 UserDomain 在通过 UserDomain 获取到 DeptDomain 在调用 DeptDomain.SetDeptName() 修改这个部门名字

      

      再比如 UserDomain.GetCustome() 获取到一个 List<CustomerDoamin> 不管业务是什么,只要用到客户列表就会执行 Select [ORM对象中的所有字段] from Customer where UserKeyId = 'XXXXXX'。

    引用关系

    0-Infrastructure
      Core2022.Enum
      Core2022.Framework.Commons
      Core2022.Framework
    1-Presentation
      Core2022.API
      Core2022.Web
        Core2022.Application.Services.DTO
        Core2022.Application.Services.Interface
    2-Application
      Core2022.Application.Services
        Core2022.Application.Services.DTO
        Core2022.Application.Services.Interface
        Core2022.Domain.Model
        Core2022.Domain.Interface
        Core2022.Repository.Interface
      Core2022.Application.Services.DTO
      Core2022.Application.Services.Interface
        Core2022.Application.Services.DTO
    3-Domain
      Core2022.Domain
        Core2022.Domain.Model
        Core2022.Domain.Interface
      Core2022.Domain.Model
      Core2022.Domain.Interface
    4-Repository
      Core2022.Repository
        Core2022.Domain.Model
        Core2022.Domain.Interface
        Core2022.Repository.Interface
      Core2022.Repository.Interface
        Core2022.Domain.Model
        Core2022.Domain.Interface

    依赖注入

    在 Startup 中配置依赖注入,实现各层之间的解耦

    InjectionServicesExtension.cs
    
    using Core2022.Framework.Attributes;
    using Core2022.Framework.Settings;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using System;
    using System.Reflection;
    
    namespace Core2022.Framework.Commons.Injections
    {
        /// <summary>
        /// 
        /// </summary>
        public static class InjectionServicesExtension
        {
            /// <summary>
            /// 通过反射注册项目中的所有服务
            /// </summary>
            /// <param name="services"></param>
            /// <param name="configuration"></param>
            /// <returns></returns>
            public static void InjectionServices(this IServiceCollection services, IConfiguration configuration)
            {
                foreach (var assemblyString in AppSettings.InjectionServices.AssemblyStrings)
                {
                    var serviceTypes = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + assemblyString).GetTypes();
                    if (serviceTypes != null && serviceTypes.Length > 0)
                    {
                        foreach (var service in serviceTypes)
                        {
                            var attribute = service.GetCustomAttribute(typeof(InjectionAttribute), false);
                            if (attribute is InjectionAttribute)
                            {
                                InjectionAttribute injectionAttribute = attribute as InjectionAttribute;
                                var serviceInterfaceName = injectionAttribute.ServiceInterfaceName;
                                var serviceLifetime = injectionAttribute.ServiceLifetime;
                                AddInjectionWithLifetime(services, serviceLifetime, serviceInterfaceName, service);
                            }
                        }
                    }
                }
            }
    
            /// <summary>
            /// 向依赖框架中注册服务
            /// </summary>
            /// <param name="services">依赖框架</param>
            /// <param name="serviceLifetime">服务生命周期</param>
            /// <param name="service">服务</param>
            /// <param name="implementation">服务的实现</param>
            /// <returns></returns>
            private static IServiceCollection AddInjectionWithLifetime(IServiceCollection services, ServiceLifetime serviceLifetime, Type service, Type implementation)
            {
                switch (serviceLifetime)
                {
                    case ServiceLifetime.Scoped:
                        return services.AddScoped(service, implementation);
                    case ServiceLifetime.Singleton:
                        return services.AddSingleton(service, implementation);
                    case ServiceLifetime.Transient:
                        return services.AddTransient(service, implementation);
                    default:
                        return services;
                }
            }
        }
    }
    InjectionAttribute.cs
    
    using Microsoft.Extensions.DependencyInjection;
    using System;
    
    
    namespace Core2022.Framework.Attributes
    {
        public class InjectionAttribute : Attribute
        {
            /// <summary>
            /// 服务依赖的接口
            /// </summary>
            public Type ServiceInterfaceName { get; set; }
    
            /// <summary>
            /// 注册服务的生命周期
            /// </summary>
            public ServiceLifetime ServiceLifetime { get; set; }
    
            /// <summary>
            /// 依赖特性
            /// </summary>
            /// <param name="name">服务依赖接口</param>
            /// <param name="serviceLifetime">服务生命周期</param>
            public InjectionAttribute(Type serviceInterfaceName, ServiceLifetime serviceLifetime = ServiceLifetime.Scoped)
            {
                ServiceInterfaceName = serviceInterfaceName;
                ServiceLifetime = serviceLifetime;
            }
        }
    }
    Startup.ConfigureServices
    
    public void ConfigureServices(IServiceCollection services)
    {
        services.InjectionInjectionOrmModel();
        //注册控制器和视图
        services.AddControllersWithViews();
        //注册服务
        services.InjectionServices(Configuration);
    }
    appsettings.json
    
    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft": "Warning",
          "Microsoft.Hosting.Lifetime": "Information"
        }
      },
      "AllowedHosts": "*",
    
      /*注册服务 配置*/
      "InjectionServices": {
        "AssemblyStrings": [
          "Core2022.Domain.Model.dll",
          "Core2022.Application.Services.dll",
          "Core2022.Domain.dll",
          "Core2022.Repository.dll"
        ]
      }
    }

    这一版代码都属于基础知识,都是固定用法

    唯一麻烦的就是编译项目的时候需要编译整个解决方案

  • 相关阅读:
    day2流程控制
    day1初识java
    SVG路径PATH
    Android开发 ---Media
    Android开发 ---ContentProvider数据提供者,Activity和Service就是上下文对象,短信监听器,内容观察者
    Android开发 ---ORMLite实现数据的增删改查,单例模式,Dao栈
    Android开发 ---SQLite数据库,lock文件,结果集游标,适配器,安全退出,给连接设置下划线,编辑器,投影,ContentValues存储,DbHelper,activity栈
    Android开发 ---多线程操作:Handler对象,消息队列,异步任务下载
    深入理解之 Android Handler
    Android开发 ---xml构建选项菜单、上下文菜单(长按显示菜单)、发通知、发送下载通知
  • 原文地址:https://www.cnblogs.com/ansheng/p/15864575.html
Copyright © 2020-2023  润新知