• 【asp.net core 系列】- 11 Service层的实现样板


    0.前言

    在《asp.net core 系列》之实战系列中,我们在之前的篇幅中对项目有了一个大概的认知,也搭建了一个基础的项目骨架。那么就让我们继续完善这个骨架,让它更加丰满。这一篇,我将带领小伙伴们一起实现用户管理功能。

    1. 数据表

    一般情况下,我们会把用户表和登录信息表放在两个表里。为什么会这样设计呢?出于以下几种考虑:

    • 使功能分割,用户信息管理是用户管理,登录是登录
    • 增加安全,降低无关信息的查询,例如访问登录接口不会连带检索用户的普通信息,当进行用户信息管理的时候,不会把登录信息也带过来

    等等

    废话不多说,直接上代码:

    namespace Data.Enums
    {
        /// <summary>
        /// 登录类型
        /// </summary>
        public enum LoginType : byte
        {
            /// token登录
            Token,
            /// 用户名密码
            Password
        }
        /// <summary>
        /// 性别
        /// </summary>
        public enum SexEnum
        {
            /// 男
            Male,
            /// 女
            Female,
            /// 隐私
            None
        }
    }
    

    SysUserAuthEntity.cs

    using Data.Enums;
    using Data.Infrastructure;
    
    namespace Data.Models
    {
        public class SysUserAuthEntity : BaseEntity<int>
        {
            public string UserName { get; set; }
            public string Password { get; set; }
            
            public LoginType LoginType { get; set;}
        }
    }
    

    SysUserInfoEntity.cs

    using System;
    using Data.Enums;
    using Data.Infrastructure;
    
    namespace Data.Models
    {
    
        public class SysUserInfoEntity : BaseEntity<int>
        {
            public string NickName { get; set; }
            public string ImageUrl { get; set; }
            public SexEnum Sex { get; set; }
            public DateTime? BirthDay { get; set; }
    
            public int SysUserAuthId { get; set; }
    
            public virtual SysUserAuthEntity SysUserAuth { get; set; }
        }
    }
    

    这里并没有使用数据库Sql语句作为数据库描述,而是使用了Entity类作为描述,这是因为数据库到实体类之间还是有一层转换,对于开发而言接触更多的是实体类,而不是数据表。

    2. 生成 Repository相关

    使用工具代码的方式有很多,我在这里推荐一种, Test项目中,添加一个测试类,具体代码如下:

    using NUnit.Framework;
    using System;
    using System.Collections.Generic;
    using System.Text;
    using Utils.Develop;
    
    namespace Test
    {
        public class DevelopTest
        {
            [Test]
            public void TetDevelop()
            {
                var d = Develop.CurrentDirect;
                Console.WriteLine(d);
                Assert.IsTrue(d.Contains("template"));
                var entities = Develop.LoadEntities();
                foreach (var item in entities)
                {
                    Console.WriteLine(item.FullName);
                }
            }
            [Test]
            public void TestCreateDevelop()
            {
                var entities = Develop.LoadEntities();
                foreach (var item in entities)
                {
                    Develop.CreateRepositoryInterface(item);
                    Develop.CreateRepositoryImplement(item);
                    Develop.CreateEntityTypeConfig(item);
                }
                Assert.Pass();
            }
        }
    }
    
    

    具体的命令行执行比较麻烦,会执行所有的测试单元:

    cd Test/
    dotnet test
    

    当然了,IDE支持单个测试单元的执行,具体操作这里就不做过多的介绍了。

    3. Service 接口和实现类

    通常Service接口会提供一个简单Crud的Service接口,然后其他业务接口继承该接口。这样可以减少代码的重复,因为重复的代码在开发过程中是非常讨厌的一种情况,因为一旦一处发生变更,其他的也有可能发生变更。所以遇到重复代码一般都会进行一定程度的封装:

    using System;
    using System.Collections.Generic;
    using System.Linq.Expressions;
    using Data.Infrastructure;
    
    namespace Service.Insfrastructure
    {
        public interface BaseService<T>
        {
            T Get(object key);
            T Get(Expression<Func<T, bool>> predicate);
    
            PageModel<T> SearchPage(PageCondition<T> condition);
    
            void Delete(Expression<Func<T, bool>> predicate);
    
            void Update(T entity);
    
            List<T> Search(Expression<Func<T, bool>> predicate);
    
        }
    }
    

    暂时就提供了这些最常见的请求方法。

    在Service.Implements项目中:

    using System;
    using System.Collections.Generic;
    using System.Linq.Expressions;
    using Data.Infrastructure;
    using Domain.Insfrastructure;
    using Service.Insfrastructure;
    
    namespace Service.Implements.Insfrastructure
    {
        public abstract class BaseServiceImpl<T> : BaseService<T>
        {
            private IRepository<T> LocalRepository { get; }
    
            protected BaseServiceImpl(IRepository<T> repository)
            {
                LocalRepository = repository;
            }
            
            
            public T Get(object key)
            {
                return LocalRepository.Get(key);
            }
    
            public T Get(Expression<Func<T, bool>> predicate)
            {
                return LocalRepository.Get(predicate);
            }
    
            public PageModel<T> SearchPage(PageCondition<T> condition)
            {
                return LocalRepository.Search(condition);
            }
    
            public void Delete(Expression<Func<T, bool>> predicate)
            {
                LocalRepository.Delete(predicate);
            }
    
            public void Update(T entity)
            {
                LocalRepository.Update(entity);
            }
    
            public List<T> Search(Expression<Func<T, bool>> predicate)
            {
                return LocalRepository.Search(predicate);
            }
        }
    }
    

    这个类设置为抽象类。

    4. 用户管理的接口

    先创建了两个简单的示范接口:

    using Data.Models;
    using Service.Insfrastructure;
    
    namespace Service
    {
        public interface ISysUserService : BaseService<SysUserInfoEntity>
        {
            void Register(SysUserAuthEntity auth, SysUserInfoEntity info);
    
            void ChangePassword(int userId, string oldPwd, string newPwd);
        }
    }
    

    实现类:

    using System;
    using Data.Models;
    using Domain.Repository;
    using Service.Implements.Insfrastructure;
    
    namespace Service.Implements
    {
        public class SysUserServiceImpl : BaseServiceImpl<SysUserInfoEntity>, ISysUserService
        {
            protected ISysUserAuthRepository AuthRepository { get; }
            protected ISysUserInfoRepository InfoRepository { get; }
    
            public SysUserServiceImpl(ISysUserAuthRepository authRepository, ISysUserInfoRepository infoRepository) : base(
                infoRepository)
            {
                AuthRepository = authRepository;
                InfoRepository = infoRepository;
            }
    
            public void Register(SysUserAuthEntity auth, SysUserInfoEntity info)
            {
                var authItem = AuthRepository.Get(p => p.LoginType == auth.LoginType && p.UserName == auth.UserName);
                if (authItem != null)
                {
                    throw new Exception("用户信息已经存在");
                }
    
                info.SysUserAuth = auth;
                InfoRepository.Insert(info);
            }
    
            public void ChangePassword(int userId, string oldPwd, string newPwd)
            {
                var info = InfoRepository.Get(userId);
                var auth = AuthRepository.Get(info.SysUserAuthId);
                if (oldPwd == null || oldPwd != auth?.Password)
                {
                    throw new Exception("原密码错误");
                }
    
                auth.Password = newPwd;
    
            }
        }
    }
    

    这里没对密码进行加密处理,直接使用明文。这在正式开发中是不允许的,密码不能使用明文保存。当然,这也不是最终代码,下一篇我们将介绍一下.net core中常见的加密实现。

    5. 总结

    这一篇通过几个简单的示例为大家介绍了一下Service层的开发逻辑以及理念。下一篇将为大家介绍一下.net core中几种简单的加密实现。

    更多内容烦请关注我的博客《高先生小屋》

    file

  • 相关阅读:
    有一种尺度叫圆融
    十大经典排序算法
    Maximal Square
    Word Break
    Flatten List
    Triangle
    Paint Fence
    Longest Increasing Continuous Subsequence
    Minimum Size Subarray Sum
    Letter Combinations of a Phone Number
  • 原文地址:https://www.cnblogs.com/c7jie/p/13173433.html
Copyright © 2020-2023  润新知