Amazing Grace

首页 新随笔 联系 管理

仓储层 Repository 实现

1.1 创建 Repository 项目

登录接口,我们用到的:登录 API,我们可以直接注入使用,这是因为 Identity,已经帮我们内置好了。

但是我们的权限相关功能,需要操作的数据库的,就需要我们自己实现。

创建项目 =》选择类库 =》输入 Electric.Repository。

框架:选择. Net 7.0。

创建完成

默认生成的 Class1.cs 可以删除。

1.2 添加类

以获取登录用户的权限列表为例,下面我们来实现,相关数据库操作功能。

1.2.1、添加类 RolePermissionRepositiory

public class RolePermissionRepositiory 
{
}

1.2.2、添加项目引用

因为我们需要操作数据库,所以需要先添加项目引用:Electric.DbMigrator

<ItemGroup>
    <ProjectReference Include="..\Electric.DbMigrator\Electric.DbMigrator.csproj" />
</ItemGroup>

1.2.3、注入数据库上下文

Web API 是支持依赖注入的,所以数据库上下文,直接在构造函数定义就可以。实现如下:

public class RolePermissionRepositiory 
{
    private readonly ApplicationDbContext _dbContext;
    public RolePermissionRepositiory(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
    }
}

1.3 RolePermissionRepositiory 接口的实现

添加方法 GetRolePermissions,根据角色名称,获取权限列表

/// <summary>
/// 获取角色权限列表
/// </summary>
/// <param name="roleName"></param>
/// <returns></returns>
public List<AccountPermissionsDto> GetRolePermissions(string roleName)
{
    var permissionsDtos = new List<AccountPermissionsDto>(permissions);
    return permissionsDtos;
}

2.1 提取接口

根据以上的步骤,我们已经定义好了:RolePermissionRepositiory。但是我们要使用依赖注入,那就需要提取接口。

接口代码如下:

public interface IRolePermissionRepositiory
{
    /// <summary>
    /// 获取角色权限列表
    /// </summary>
    /// <param name="roleName"></param>
    /// <returns></returns>
    List<AccountPermissionsDto> GetRolePermissions(string roleName);
}

改为继承接口 IRolePermissionRepositiory,完整代码如下:

public class RolePermissionRepositiory : IRolePermissionRepositiory
{
    private readonly ApplicationDbContext _dbContext;
    public RolePermissionRepositiory(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
    }
    public List<AccountPermissionsDto> GetRolePermissions(string roleName)
    {
        var permissionsDtos = new List<AccountPermissionsDto>(permissions);
        return permissionsDtos;
    }
}

2.2 添加项目依赖

先为 Eletric.API 添加项目依赖:Electric.Repository

<ProjectReference Include="..\Electric.Repository\Electric.Repository.csproj" />

Repository 依赖注入

2.3 项目入口添加依赖

在 Program.cs,添加如下代码,实现依赖注入。

builder.Services.AddTransient(typeof(IRolePermissionRepositiory), typeof(RolePermissionRepositiory));

依赖注入有 3 中方法:AddTransient、AddScoped、AddSingleton,区别如下:

  • AddTransient:无论是不是同一个请求(同一个请求里的不同服务)同一个客户端,每次都是创建新的实例;

  • AddScoped: 对于同一个请求返回同一个实例,不同的请求返回不同的实例;

  • AddSingleton: 每次都是获得同一个实例, 单一实例模式。

2.4 RolePermissionRepositiory 依赖注入使用

在构造函数注入依赖:IRolePermissionRepositiory,这样我们就访问数据库了。

同时我们还添加其他两个依赖:IHttpContextAccessor、UserManager

IHttpContextAccessor 这个是 Http 上下文,因为我们获取登录信息,所以要添加这个注入,同时这个是 Web API 默认注入的,我们可以直接使用。

public class AccountsController : ControllerBase
{
    private readonly IRolePermissionRepositiory _rolePermissionRepositiory;
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly UserManager<EleUser> _userManager;

    public AccountsController(IRolePermissionRepositiory rolePermissionRepositiory, IHttpContextAccessor httpContextAccessor, UserManager<EleUser> userManager)
    {
        _rolePermissionRepositiory = rolePermissionRepositiory;
        _httpContextAccessor = httpContextAccessor;
        _userManager = userManager;
    }
}

2.5 实现接口功能

我们在数据库注入后,我们就可以直接使用了,使用方式如下:

完整代码如下:

[HttpGet("permissions")]
public async Task<IActionResult> GetPermissions()
{
    var userName = _httpContextAccessor.HttpContext.User.Identity.Name;
    var entity = await _userManager.FindByNameAsync(userName);
    var roles = await _userManager.GetRolesAsync(entity);
    var rolePermissions = new Dictionary<long, AccountPermissionsDto>();
    foreach (var roleName in roles)
    {
        var _rolePermissions = _rolePermissionRepositiory.GetRolePermissions(roleName);
        foreach (var permission in _rolePermissions)
        {
            if(!rolePermissions.ContainsKey(permission.Id))
            {
                rolePermissions.Add(permission.Id, permission);
            }
        }
    }
    var list = rolePermissions.Values.ToList();
    return Ok(list);
}

2.6 测试接口

运行项目,测试下 GetPermissions 接口,就能看到 Http 状态码为 200,可以正常返回。

说明:依赖注入是成功的,这边返回空列表,这是因为我们 Repository 还未实现相关功能。

2.7 重构依赖注入

通过上面步骤的介绍,我们通过以下代码就可以完成依赖注入。

但是,如果未来我们的业务系统,功能越来越多,就会有很多相关的 Repository,这样就需要每个都要注入。

所以,我们可以采用反射机制,来自动获取并注入。

先定义一个父类:BaseRepository

namespace Electric.Repository
{
    public class BaseRepository
    {
    }
}

让所有 Repositiory 继承 BaseRepository。

并在项目入口 Program.cs,修改依赖注入代码:

//添加注入
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach(var assembly in assemblies)
{
    //获取继承BaseRepository的类
    List<Type> types = assembly.GetTypes()
        .Where(t => t.BaseType == typeof(BaseRepository))
        .ToList();

    types.ForEach(impl =>
    {
        //获取该类所继承的所有接口
        Type[] interfaces = impl.GetInterfaces();
        interfaces.ToList().ForEach(i =>
        {
            builder.Services.AddTransient(i, impl);
        });
    });
}

如果我们此时,运行项目,进行用户信息接口测试,会发现会报错。

这是因为我们,在项目入口的注入这边,GetAssemblies 只获取使用过的程序集,未使用的程序集不会包含其中,所以我们要进行修改。

先添加 AssemblyExtension 扩展。


using System.Reflection;

namespace Electric.API.Extensions
{
    /// <summary>
    /// Assembly扩展
    /// </summary>
    public static class AssemblyExtension
    {
        /// <summary>
        /// 获取所有程序集
        /// </summary>
        /// <param name="domain"></param>
        /// <returns></returns>
        public static List<Assembly> GetReferanceAssemblies(this AppDomain domain)
        {
            var list = new List<Assembly>();
            domain.GetAssemblies().ToList().ForEach(i =>
            {
                GetReferanceAssemblies(i, list);
            });
            return list;
        }
        static void GetReferanceAssemblies(Assembly assembly, List<Assembly> list)
        {
            assembly.GetReferencedAssemblies().ToList().ForEach(i =>
            {
                var ass = Assembly.Load(i);
                if (!list.Contains(ass))
                {
                    list.Add(ass);
                    GetReferanceAssemblies(ass, list);
                }
            });
        }
    }
}

在项目入口,修改注入,GetAssemblies 修改为 GetReferanceAssemblies。

再次运行项目,测试下 GetPermissions 接口,就能看到 Http 状态码为 200,可以正常返回。

说明:依赖注入是成功的。

Automapper映射

我们上面的步骤,并未真正的实现数据库操作,下面一起来完成,并演示如何使用 AutoMapper。

3.1 先添加引用 AutoMapper

先为项目 Electric.Entity,添加引用:AutoMapper,版本 12.0.1。

<PackageReference Include="AutoMapper" Version="12.0.1" />

3.2 创建映射对象关系

以下代码创建映射关系:ElePermission 可以转化为 AccountPermissionsDto。

如果要 AccountPermissionsDto 可以转化为 ElePermission,要添加对应代码:

CreateMap<AccountPermissionsDto, ElePermission>();

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<ElePermission, AccountPermissionsDto>();
    }

    public static IMapper CreateMapper()
    {
        //创建配置对象
        var configuration = new MapperConfiguration(cfg =>
        {
            cfg.AddProfile<MappingProfile>();
        });
        //创建映射对象
        var mapper = configuration.CreateMapper();

        return mapper;
    }
}

3.3 实现接口功能


以下代码,实现:从数据库获取权限列表,并转化对象。

public List<AccountPermissionsDto> GetRolePermissions(string roleName)
{
    //根据角色获取权限列表
    var permissions = (from p in _dbContext.ElePermission
                        join rp in _dbContext.EleRolePermission on p.Id equals rp.PermissionId
                        join r in _dbContext.Roles on rp.RoleId equals r.Id
                        where r.NormalizedName == roleName
                        select p
                ).ToList();

    //对象映射转化
    var permissionsDtos = _mapper.Map<List<AccountPermissionsDto>>(permissions);

    return permissionsDtos;
}

运行项目,在浏览器测试接口,结果如下,可以正确的返回权限列表。

3.4 重构为依赖注入

我们在项目实际开发中,可能会创建多个映射对象关系【见 3.2】。

这就会导致我们需要了解多个映射对象关系的内容,我们可以改为依赖注入,这样方便我们使用。

3.4.1 项目入口添加依赖注入

在 Program.cs,添加如下代码:

AutoMapper.IConfigurationProvider config = new MapperConfiguration(cfg =>
{
    cfg.AddProfile<MappingProfile>();
});
builder.Services.AddSingleton(config);
builder.Services.AddScoped<IMapper, Mapper>();

3.4.2 添加注入对象

在 Repositiory 的构造函数添加注入 IMapper

public class RolePermissionRepositiory : BaseRepository, IRolePermissionRepositiory
{
    private readonly ApplicationDbContext _dbContext;
    private readonly IMapper _mapper;
    public RolePermissionRepositiory(ApplicationDbContext dbContext, IMapper mapper)
    {
        _dbContext = dbContext;
        _mapper = mapper;
    }
}

3.4.3 修改接口功能

修改:获取角色权限列表【见 3.3】,代码如下:

public List<AccountPermissionsDto> GetRolePermissions(string roleName)
{
    var permissions = (from p in _dbContext.ElePermission
    join rp in _dbContext.EleRolePermission on p.Id equals rp.PermissionId
    join r in _dbContext.Roles on rp.RoleId equals r.Id
    where r.NormalizedName == roleName
    select p
    ).ToList();
    var permissionsDtos = _mapper.Map<List<AccountPermissionsDto>>(permissions);
    return permissionsDtos;
}

运行项目,在浏览器测试接口,结果如下,可以正确的返回权限列表。

测试获取用户信息,结果如下,可以正常返回:

posted on 2024-04-29 11:09  AmazingCookie  阅读(3)  评论(0编辑  收藏  举报