• DDD 异步方法、读写分离、数据库日志完善、用户信息


    使用 .NET Core 从零开始写一个 DDD 领域模型的框架

    每一篇文章打一个 tag

    Github 地址,tag 地址

    这版代码

      异步方法

      读写分离

      数据库日志

      全局登陆信息

    数据库日志完善

    public class AutofacFilter : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            DateTime startTime = DateTime.Now;
            //objs 是当前拦截方法的入参
            object[] objs = invocation.Arguments;
            invocation.Proceed();
            // ret 是当前方法的返回值
            object ret = invocation.ReturnValue;
            DateTime endTime = DateTime.Now;
    
            if (invocation.Method.CustomAttributes?.FirstOrDefault(i => i.AttributeType.Name == "AOPLogAttribute") != null)
            {
                if (invocation.Method.Name == "FindAsync")
                {
                    var taskType = ret.GetType();
    
                    IBaseDomain domain = (IBaseDomain)taskType.GetProperty("Result").GetValue(ret);
              // 这两行为什么要这么写,在异步方法哪里解释
    BaseOrmModel model
    = domain.GetModel(); DBLogSeleteModel logModel = new DBLogSeleteModel() { CreateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), StartTimer = startTime, EndTimer = endTime, TakeTime = (endTime - startTime).TotalMilliseconds.ToString(), ReturnValue = JsonConvert.SerializeObject(model), OperatorKeyId = AuthorizationUtil.GetOperatorKeyId(), OperatorUserkeyId = AuthorizationUtil.GetCurrentUserKeyId(), OperatorUserName = AuthorizationUtil.GetCurrentUserName(), }; DBLog.WriteLog(logModel); } } } }

      上个版本已经有了 修改和新增的日志了,这回把 查询的给补上。(删除是逻辑删除,包含在修改里面了)

    异步方法

    IDomain Find(Guid keyId, bool readOnly = false);
    
    Task<IBaseDomain> FindAsync(Guid keyId, bool readOnly = false);
    
    IList<IDomain> FindList(Expression<Func<OrmEntity, bool>> predicate, bool readOnly = false);
    
    Task<IList<IDomain>> FindListAsync(Expression<Func<OrmEntity, bool>> predicate, bool readOnly = false);

      仓储层,在原有方法的基础上,添加异步方法

    public async Task<bool> UpdateUser(UserRequestDto request)
    {
        IUserDomain userDomain = UserRepository.Find(request.KeyId);
        userDomain.SetUserName(request.UserName);
        userDomain.SetPassWord(request.PassWord);
        userDomain.SetLastLoginTime(DateTime.Now);
    
        return await SaveChangesAsync() > 0;
    }
    public async Task<UserResponseDto> Find(UserRequestDto request)
    {
        IBaseDomain baseDomain = await UserRepository.FindAsync(request.KeyId);
        IUserDomain userDomain = (IUserDomain)baseDomain;
        UserResponseDto respDto = new UserResponseDto()
        {
            KeyId = userDomain.GetKeyId(),
            CreateUserKeyId = userDomain.GetCreateUserKeyId(),
            UpdateUserKeyId = userDomain.GetUpdateUserKeyId(),
            。。。
        };
        return respDto;
    }

      业务层,应用层,表现层全部统一使用异步方法

      异步方法并不能减少单个请求响应的时间。(FindAsync、SaveChangeAsync、ToListAsync 等异步方法并不会节省时间)

      但是可以提高整体的并发量,可以用更少的线程完成更多的响应。

      但是异步方法也带来了一些很麻烦的问题。

      问题一:逆变与协变
        在 AutofacFilter 方法拦截器中对异步方法 FindAsync 进行拦截的时候出现了逆变协变的问题
        object ret = invocation.ReturnValue; // FindAsync 执行完毕后的返回值类型为 Task<IUserDomain>
        Task<IBaseDomain> domain = (Task<IBaseDomain>)ret; // 在执行的时候是会抛异常的。
        由于 Task 中没有提供逆变与协变的重载所以Task<子类> 子类 = Task<父类> 是不可以的
        解决方式:通过反射直接调用 Task 的 Result 方法。把 Result 强制转换成 IBaseDomain 就行了
      问题二:不能任何情况下都使用异步方法
        SaveChangeAsync 与 FindAsync 方法互斥
        一个 ORM对象 使用 FindAsync 获取,就只能用 SaveChange 方法保存
        一个 ORM对象 使用 SaveChangeAsync 方法保存,就只能用 Find 获取


    读写分离

      interface IUnitOfWork
      interface IAppUnitOfWork : IUnitOfWork
      interface IReadUnitOfWork : IUnitOfWork
      class AppUnitOfWork : IAppUnitOfWork
      class ReadUnitOfWork : IReadUnitOfWork

      定义了一个读写的工作单元,一个只读的工作单元

      通过 AppUnitOfWorkFactory 创建指定的工作单元

      仓储层中所有的方法都要添加一个 bool readOnly = false 参数,用来控制程序使用那个数据库

      这个Demo中读库和写库链接的是同一个数据库,但是该有的东西还是要弄一下,后续看情况弄一套真实的读库和写库

      只读的 UnitOfWork 不提供修改数据库的方法

      在业务层、领域层 手动确定是从读库拿数据还是从写库拿数据

    登陆信息线程内唯一

      通过Action执行前的Filter把Cookie中的用户信息写入到当前请求的线程中

      单元测试中直接把用户登陆信息写死到线程中

      异步方法切换线程的时候会把当前线程中的信息复制到切换的线程中

  • 相关阅读:
    CentOS下Apache开启Rewrite功能
    CentOS下Apache配置多域名或者多端口映射
    CentOS配置SVN服务器
    Windows下Apache配置域名
    PHP 返回13位时间戳
    主成分分析(PCA)特征选择算法详解
    均值、方差、标准差及协方差、协方差矩阵详解
    Jackson序列化日期类型的属性
    监控JVM内存使用情况,剩余空间小于2M时报警
    java 7中新增的CPU和负载的监控
  • 原文地址:https://www.cnblogs.com/ansheng/p/15874274.html
Copyright © 2020-2023  润新知