• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

愚公系列2023年03月 MES生产制造执行系统-001.Autofac的使用

武飞扬头像
愚公搬代码
帮助1


前言

IoC容器是一种设计模式,它可以管理应用程序中的对象依赖关系。它可以自动创建和注入对象,从而减少了代码的耦合度和重复性。

Autofac是Microsoft .NET的IoC容器。它管理类之间的依赖关系,以便应用程序在大小和复杂性增加时易于更改。这是通过将常规 .NET 类视为组件来实现的。

Autofac的官网:https://autofac.org/
学新通

Autofac的源码网址:https://gitee.com/dennisdyh/Autofac.Extensions.DependencyInjection
学新通

一、Autofac的使用

1.安装包

Autofac.Extensions.DependencyInjection

学新通

2.服务注入

在Program注入Autofac服务

public static IHostBuilder CreateHostBuilder(string[] args) =>
       Host.CreateDefaultBuilder(args)
           .ConfigureWebHostDefaults(webBuilder =>
           {
               webBuilder.ConfigureKestrel(serverOptions =>
               {
                   serverOptions.Limits.MaxRequestBodySize = 10485760;
                   // Set properties and call methods on options
               });
               webBuilder.UseKestrel().UseUrls("http://*:9991");
               webBuilder.UseIIS();
               webBuilder.UseStartup<Startup>();
           }).UseServiceProviderFactory(new AutofacServiceProviderFactory());//设置工厂来替换实例

学新通
在Startup中增加ConfigureContainer方法,用来配置映射关系

public void ConfigureContainer(ContainerBuilder builder)
{
    Services.AddModule(builder, Configuration);
}

使用了Autofac以后,在IServiceCollection中注入的服务,也能生效;因为Autofac是先接受了所有的来自于IServiceCollection的服务映射后,再去读取ConfigureContainer方法中配置的映射。
学新通

3.AddModule扩展方法详解

AddModule包含了反射注入容器和一堆服务注入容器

//  private static bool _isMysql = false;
public static IServiceCollection AddModule(this IServiceCollection services, ContainerBuilder builder, IConfiguration configuration)
{
    //services.AddSession();
    //services.AddMemoryCache();
    //初始化配置文件
    AppSetting.Init(services, configuration);
    Type baseType = typeof(IDependency);
    var compilationLibrary = DependencyContext.Default
        .RuntimeLibraries
        .Where(x => !x.Serviceable
        && x.Type == "project")
        .ToList();
    var count1 = compilationLibrary.Count;
    List<Assembly> assemblyList = new List<Assembly>();

    foreach (var _compilation in compilationLibrary)
    {
        try
        {
            assemblyList.Add(AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(_compilation.Name)));
        }
        catch (Exception ex)
        {
            Console.WriteLine(_compilation.Name   ex.Message);
        }
    }
    builder.RegisterAssemblyTypes(assemblyList.ToArray())
     .Where(type => baseType.IsAssignableFrom(type) && !type.IsAbstract)
     .AsSelf().AsImplementedInterfaces()
     .InstancePerLifetimeScope();
    builder.RegisterType<UserContext>().InstancePerLifetimeScope();
    builder.RegisterType<ActionObserver>().InstancePerLifetimeScope();
    //model校验结果
    builder.RegisterType<ObjectModelValidatorState>().InstancePerLifetimeScope();
    string connectionString = DBServerProvider.GetConnectionString(null);

    if (DBType.Name == DbCurrentType.MySql.ToString())
    {
        //增加dapper对mysql字段Guid映射
        SqlMapper.AddTypeHandler(new DapperParseGuidTypeHandler());
        SqlMapper.RemoveTypeMap(typeof(Guid?));

        //services.AddDbContext<SysDbContext>();
        //mysql8.x的版本使用Pomelo.EntityFrameworkCore.MySql 3.1会产生异常,需要在字符串连接上添加allowPublicKeyRetrieval=true
        services.AddDbContextPool<SysDbContext>(optionsBuilder => { optionsBuilder.UseMySql(connectionString); }, 64);
        services.AddDbContextPool<ServiceDbContext>(optionsBuilder => { optionsBuilder.UseMySql(connectionString); }, 64);
        services.AddDbContextPool<ReportDbContext>(optionsBuilder => { optionsBuilder.UseMySql(connectionString); }, 64);
    }
    else if (DBType.Name == DbCurrentType.PgSql.ToString())
    {
        services.AddDbContextPool<SysDbContext>(optionsBuilder => { optionsBuilder.UseNpgsql(connectionString); }, 64);
        services.AddDbContextPool<ServiceDbContext>(optionsBuilder => { optionsBuilder.UseNpgsql(connectionString); }, 64);
        services.AddDbContextPool<ReportDbContext>(optionsBuilder => { optionsBuilder.UseNpgsql(connectionString); }, 64);
    }
    else
    {
        services.AddDbContextPool<SysDbContext>(optionsBuilder => { optionsBuilder.UseSqlServer(connectionString); }, 64);
        services.AddDbContextPool<ServiceDbContext>(optionsBuilder => { optionsBuilder.UseSqlServer(connectionString); }, 64);
        services.AddDbContextPool<ReportDbContext>(optionsBuilder => { optionsBuilder.UseSqlServer(connectionString); }, 64);
    }
    //启用缓存
    if (AppSetting.UseRedis)
    {
        builder.RegisterType<RedisCacheService>().As<ICacheService>().SingleInstance();
    }
    else
    {
        builder.RegisterType<MemoryCacheService>().As<ICacheService>().SingleInstance();
    }
    //kafka注入
    //if (AppSetting.Kafka.UseConsumer)
    //    builder.RegisterType<KafkaConsumer<string, string>>().As<IKafkaConsumer<string, string>>().SingleInstance();
    //if (AppSetting.Kafka.UseProducer)
    //    builder.RegisterType<KafkaProducer<string, string>>().As<IKafkaProducer<string, string>>().SingleInstance();
    return services;
}

学新通

3.1 AppSetting.Init

应用程序初始化主要是对配置文件使用

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "VirtualPath": {
    "StaticFile": "E:\\Web\\Static", //配置的虚拟目录文件所在路径
    "FolderName": "/Static" //访问时此路径时的别名
  },
  "AppUrls": {
  },
  "Connection": {
    "DBType": "MsSql", //MySql/MsSql/PgSql  //数据库类型,如果使用的是sqlserver此处应设置为MsSql
    //sqlserver连接字符串
    "DbConnectionString": "Data Source=.;Initial Catalog=iMES_Open;Persist Security Info=True;User ID=sa;Password=1;Connect Timeout=500;",

    //mysql连接字符串(升级EFCore3.1到时已将mysql连接字符串修改,2019-12-20)
    //"DbConnectionString": " Data Source=127.0.0.1;Database=imes_open;AllowLoadLocalInfile=true;User ID=root;Password=123456;allowPublicKeyRetrieval=true;pooling=true;CharSet=utf8;port=3306;sslmode=none;",

    //PgSql连接字符串
    //  "DbConnectionString": "Host=132.232.2.109;Port=5432;User id=postgres;password=jxx_abcd;Database=netcoredev;",
    "RedisConnectionString": "127.0.0.1,Password=123456,SyncTimeout=15000", //redis连接字符串(最好加密)
    "UseRedis": "false", //是否使用redis,如果不使用,默认使用Memory内置缓存
    "UseSignalR": "true" //是否使用SignalR(2022.05.03),注意需要将端的地址配置到下面的CorsUrls属性中
  },
  //业务数据库连接
  "ServiceConnectingString": "Data Source=.;Initial Catalog=iMES;Persist Security Info=True;User ID=sa;Password=123456;Connect Timeout=500;",
  //报表数据库连接
  "ReportConnectingString": "Data Source=.;Initial Catalog=iMES;Persist Security Info=True;User ID=sa;Password=123456;Connect Timeout=500;",
  "Secret": { //秘钥配置
    "JWT": "BB3647441FFA4B5DB4E64A29B53CE525", //JWT
    "Audience": "iMES.core",
    "Issuer": "iMES.core.owner",
    "User": "C5ABA9E202D94C43A3CA66002BF77FAF", //
    "DB": "3F8B7B38AD3D484A89ACA513CBD79F36",
    "Redis": "E6D90DDBC70C4F4EA3C312B6FCB473C8"
  },
  //================跨域请求 (CORS)配置(2019-12-20新增),
  //================.netcore3.1必须配置此属性,多个url用豆号隔开,url为vue站点的地址,可以将发布后的地址也同时配置上
  "CorsUrls": "http://localhost:8081,http://localhost:8082,http://localhost:8080,http://localhost:7080,http://localhost:9980,http://127.0.0.1:9980,http://localhost:9990,http://www.volcore.xyz,http://app.625sc.com,https://imes.625sc.com",
  "ExpMinutes": "120", //JWT有效期(分钟=默认120),
  "CreateMember": { //对表插入数据时,需要记录创建人/创建时间/创建日期,配置UserIdField/UserNameField/DateField分别为对应数据库的创建人CreateID,创建人Creator,创建时间CreateDate字段(新建数据时,由框架默认完成给这几个字段赋值,字段区分大小写)或可手动调用T.SetCreateDefaultVal()完成设置创建人/创建时间/创建日期
    //如果表的主键是GUID,界面查询时默认会用到DateField对应的实体(数据库)字段进行排序
    "UserIdField": "CreateID",
    "UserNameField": "Creator",
    "DateField": "CreateDate"
  },
  "ModifyMember": { //修改同上
    "UserIdField": "ModifyID",
    "UserNameField": "Modifier",
    "DateField": "ModifyDate"
  }, //演示系统过滤Action,只有超级管理员才能操作,其他用户只有只读权限
  "GlobalFilter": {
    "Message": "演示环境,当前帐号没有开启此功能权限",
    "Enable": "false", //开启Action过滤
    "Actions": [ "Update", "Del", "Add", "SavePermission", "Save", "CreatePage", "CreateVuePage", "CreateEntityModel", "SaveEidt", "CreateServices", "Import", "Upload", "Audit", "ModifyPwd" ]
  },
  "Kafka": {
    //是否使用生产者
    "UseProducer": false,
    "ProducerSettings": {
      "BootstrapServers": "192.168.20.241:9092", //confluent cloud bootstrap servers
      "SaslMechanism": "Plain",
      "SecurityProtocol": "SaslSsl",
      "SaslUsername": "<confluent cloud key>",
      "SaslPassword": "<confluent cloud secret>"
    },
    //是否使用消费者
    "UseConsumer": false,
    //是否持续监听消费者订阅 用于while循环订阅
    "IsConsumerSubscribe": true,
    "ConsumerSettings": {
      "BootstrapServers": "192.168.20.241:9092", //confluent cloud bootstrap servers
      "GroupId": "amcl_group", //web-example-group
      "SaslMechanism": "Plain",
      "SecurityProtocol": "SaslSsl",
      "SaslUsername": "<confluent cloud key>",
      "SaslPassword": "<confluent cloud secret>"
    },
    "Topics": {
      "TestTopic": "alarm_topic"
    }
  },
  "Mail": {
    "Address": "zm_rid@163.com", //发件的邮箱
    "Host": "smtp.163.com",
    "Name": "iMES", //发送人名称
    "Port": 25,
    "EnableSsl": false,
    "AuthPwd": "授权密码" //授权密码(对应邮箱设置里面去开启)
  },
  "QuartzAccessKey": "65EC9387312E4717810C552963CE59FF", //定时任务的值
  "ExportPDFPath": "C:\\iMES_Open\\iMES_Front\\PDF" //导出PDF路径
}

学新通

public static void Init(IServiceCollection services, IConfiguration configuration)
{
    //---------------------------------配置信息服务类的映射------------------------------
    Configuration = configuration;
    services.Configure<Secret>(configuration.GetSection("Secret"));
    services.Configure<Connection>(configuration.GetSection("Connection"));
    services.Configure<CreateMember>(configuration.GetSection("CreateMember"));
    services.Configure<ModifyMember>(configuration.GetSection("ModifyMember"));
    services.Configure<GlobalFilter>(configuration.GetSection("GlobalFilter"));
    services.Configure<Kafka>(configuration.GetSection("Kafka"));
    //---------------------------------获取当前程序目录-----------------------------------
    var provider = services.BuildServiceProvider();
    IWebHostEnvironment environment = provider.GetRequiredService<IWebHostEnvironment>();
    CurrentPath = Path.Combine(environment.ContentRootPath, "").ReplacePath();
    //---------------------------------获取各种配置操作类-------------------------------------
    Secret = provider.GetRequiredService<IOptions<Secret>>().Value;

    //设置修改或删除时需要设置为默认用户信息的字段
    CreateMember = provider.GetRequiredService<IOptions<CreateMember>>().Value ?? new CreateMember();
    ModifyMember = provider.GetRequiredService<IOptions<ModifyMember>>().Value ?? new ModifyMember();
    //全局过滤行为
    GlobalFilter = provider.GetRequiredService<IOptions<GlobalFilter>>().Value ?? new GlobalFilter();

    GlobalFilter.Actions = GlobalFilter.Actions ?? new string[0];
    //Kafka消息队列
    Kafka = provider.GetRequiredService<IOptions<Kafka>>().Value ?? new Kafka();
    //各种数据库和缓存数据库连接字符串
    _connection = provider.GetRequiredService<IOptions<Connection>>().Value;
    //JWT过期时间
    ExpMinutes = (configuration["ExpMinutes"] ?? "120").GetInt();

    //判断数据库是否存在
    DBType.Name = _connection.DBType;
    if (string.IsNullOrEmpty(_connection.DbConnectionString))
        throw new System.Exception("未配置好数据库默认连接");
    //进行数据库解密(解密失败返回原字符串,成功返回新字符串)
    try
    {
        _connection.DbConnectionString = _connection.DbConnectionString.DecryptDES(Secret.DB);
    }
    catch { }

    if (!string.IsNullOrEmpty(_connection.RedisConnectionString))
    {
        try
        {
            _connection.RedisConnectionString = _connection.RedisConnectionString.DecryptDES(Secret.Redis);
        }
        catch { }
    }

}

学新通

3.1.1 数据库字符串加/解密
public static class SecurityEncDecryptExtensions
{

    private static byte[] Keys = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
    /// <summary> 
    /// DES加密字符串 
    /// </summary> 
    /// <param name="encryptString">待加密的字符串</param> 
    /// <param name="encryptKey">加密密钥,要求为16位</param> 
    /// <returns>加密成功返回加密后的字符串,失败返回源串</returns> 

    public static string EncryptDES(this string encryptString, string encryptKey)
    {
        try
        {
            byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 16));
            byte[] rgbIV = Keys;
            byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);

            using (var DCSP = Aes.Create())
            {
                using (MemoryStream mStream = new MemoryStream())
                {
                    using (CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write))
                    {
                        cStream.Write(inputByteArray, 0, inputByteArray.Length);
                        cStream.FlushFinalBlock();
                        return Convert.ToBase64String(mStream.ToArray()).Replace(' ', '_').Replace('/', '~');
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw new Exception("密码加密异常"   ex.Message);
        }

    }

    /// <summary> 
    /// DES解密字符串 
    /// </summary> 
    /// <param name="decryptString">待解密的字符串</param> 
    /// <param name="decryptKey">解密密钥,要求为16位,和加密密钥相同</param> 
    /// <returns>解密成功返回解密后的字符串,失败返源串</returns> 

    public static string DecryptDES(this string decryptString, string decryptKey)
    {
        byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey.Substring(0, 16));
        byte[] rgbIV = Keys;
        byte[] inputByteArray = Convert.FromBase64String(decryptString.Replace('_', ' ').Replace('~', '/'));
        using (var DCSP = Aes.Create())
        {
            using (MemoryStream mStream = new MemoryStream())
            {
                using (CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write))
                {
                    byte[] inputByteArrays = new byte[inputByteArray.Length];
                    cStream.Write(inputByteArray, 0, inputByteArray.Length);
                    cStream.FlushFinalBlock();
                    return Encoding.UTF8.GetString(mStream.ToArray());
                }
            }
        }

    }
    public static bool TryDecryptDES(this string decryptString, string decryptKey, out string result)
    {
        result = "";
        try
        {
            result = DecryptDES(decryptString, decryptKey);
            return true;
        }
        catch
        {
            return false;
        }
    }
}

学新通

3.2 Autofac相关服务类

3.2.1 UserContext

UserContext主要作用就是记录用户信息

public class UserContext
{
    /// <summary>
    /// 为了尽量减少redis或Memory读取,保证执行效率,将UserContext注入到DI,
    /// 每个UserContext的属性至多读取一次redis或Memory缓存从而提高查询效率
    /// </summary>
    public static UserContext Current
    {
        get
        {
            return Context.RequestServices.GetService(typeof(UserContext)) as UserContext;
        }
    }

    private static Microsoft.AspNetCore.Http.HttpContext Context
    {
        get
        {
            return Utilities.HttpContext.Current;
        }
    }
    private static ICacheService CacheService
    {
        get { return GetService<ICacheService>(); }
    }

    private static T GetService<T>() where T : class
    {
        return AutofacContainerModule.GetService<T>();
    }

    public UserInfo UserInfo
    {
        get
        {
            if (_userInfo != null)
            {
                return _userInfo;
            }
            return GetUserInfo(UserId);
        }
    }

    private UserInfo _userInfo { get; set; }

    /// <summary>
    /// 角色ID为1的默认为超级管理员
    /// </summary>
    public bool IsSuperAdmin
    {
        get { return IsRoleIdSuperAdmin(this.RoleId); }
    }
    /// <summary>
    /// 角色ID为1的默认为超级管理员
    /// </summary>
    public static bool IsRoleIdSuperAdmin(int roleId)
    {
        return roleId == 1;
    }

    public UserInfo GetUserInfo(int userId)
    {
        if (_userInfo != null) return _userInfo;
        if (userId <= 0)
        {
            _userInfo = new UserInfo();
            return _userInfo;
        }
        string key = userId.GetUserIdKey();
        _userInfo = CacheService.Get<UserInfo>(key);
        if (_userInfo != null && _userInfo.User_Id > 0) return _userInfo;

        _userInfo = DBServerProvider.DbContext.Set<Sys_User>()
            .Where(x => x.User_Id == userId).Select(s => new UserInfo()
            {
                User_Id = userId,
                Role_Id = s.Role_Id.GetInt(),
                RoleName = s.RoleName,
                //2022.08.15增加部门id
                DeptId = s.Dept_Id??0,
                Token = s.Token,
                UserName = s.UserName,
                UserTrueName = s.UserTrueName,
                Enable = s.Enable
            }).FirstOrDefault();

        if (_userInfo != null && _userInfo.User_Id > 0)
        {
            CacheService.AddObject(key, _userInfo);
        }
        return _userInfo ?? new UserInfo();
    }

    /// <summary>
    /// 获取角色权限时通过安全字典锁定的角色id
    /// </summary>
    private static ConcurrentDictionary<string, object> objKeyValue = new ConcurrentDictionary<string, object>();

    /// <summary>
    /// 角色权限的版本号
    /// </summary>
    private static readonly Dictionary<int, string> rolePermissionsVersion = new Dictionary<int, string>();

    /// <summary>
    /// 每个角色ID对应的菜单权限(已做静态化处理)
    /// 每次获取权限时用当前服务器的版本号与redis/memory缓存的版本比较,如果不同会重新刷新缓存
    /// </summary>
    private static readonly Dictionary<int, List<Permissions>> rolePermissions = new Dictionary<int, List<Permissions>>();



    /// <summary>
    /// 获取用户所有的菜单权限
    /// </summary>

    public List<Permissions> Permissions
    {
        get
        {
            return GetPermissions(RoleId);
        }
    }

    /// <summary>
    /// 菜单按钮变更时,同时刷新权限缓存2022.05.23
    /// </summary>
    /// <param name="menuId"></param>
    public void RefreshWithMenuActionChange(int menuId)
    {
        foreach (var roleId in rolePermissions.Where(c => c.Value.Any(x => x.Menu_Id == menuId)).Select(s => s.Key))
        {
            if (rolePermissionsVersion.ContainsKey(roleId))
            {
                CacheService.Add(roleId.GetRoleIdKey(), DateTime.Now.ToString("yyyyMMddHHMMssfff"));
            }
        }

    }

    /// <summary>
    /// 获取单个表的权限
    /// </summary>
    /// <param name="tableName"></param>
    /// <returns></returns>
    public Permissions GetPermissions(string tableName)
    {
        return GetPermissions(RoleId).Where(x => x.TableName == tableName).FirstOrDefault();
    }
    /// <summary>
    /// 2022.03.26
    /// 菜单类型1:移动端,0:PC端
    /// </summary>
    public static int MenuType
    {
        get
        {
            return Context.Request.Headers.ContainsKey("uapp") ? 1 : 0;
        }
    }
    /// <summary>
    /// 自定条件查询权限
    /// </summary>
    /// <param name="func"></param>
    /// <returns></returns>
    public Permissions GetPermissions(Func<Permissions, bool> func)
    {
        // 2022.03.26增移动端加菜单类型判断
        return GetPermissions(RoleId).Where(func).Where(x => x.MenuType == MenuType).FirstOrDefault();
    }

    private List<Permissions> ActionToArray(List<Permissions> permissions)
    {
        permissions.ForEach(x =>
        {
            try
            {
                var menuAuthArr = x.MenuAuth.DeserializeObject<List<Sys_Actions>>();
                x.UserAuthArr = string.IsNullOrEmpty(x.UserAuth)
                ? new string[0]
                : x.UserAuth.Split(",").Where(c => menuAuthArr.Any(m => m.Value == c)).ToArray();

            }
            catch { }
            finally
            {
                if (x.UserAuthArr == null)
                {
                    x.UserAuthArr = new string[0];
                }
            }
        });
        return permissions;
    }
    private List<Permissions> MenuActionToArray(List<Permissions> permissions)
    {
        permissions.ForEach(x =>
        {
            try
            {
                x.UserAuthArr = string.IsNullOrEmpty(x.UserAuth)
                ? new string[0]
                : x.UserAuth.DeserializeObject<List<Sys_Actions>>().Select(s => s.Value).ToArray();
            }
            catch { }
            finally
            {
                if (x.UserAuthArr == null)
                {
                    x.UserAuthArr = new string[0];
                }
            }
        });
        return permissions;
    }
    public List<Permissions> GetPermissions(int roleId)
    {
        if (IsRoleIdSuperAdmin(roleId))
        {
            //2020.12.27增加菜单界面上不显示,但可以分配权限
            var permissions = DBServerProvider.DbContext.Set<Sys_Menu>()
                .Where(x => x.Enable == 1 || x.Enable == 2)
                .Select(a => new Permissions
                {
                    Menu_Id = a.Menu_Id,
                    ParentId = a.ParentId,
                    //2020.05.06增加默认将表名转换成小写,权限验证时不再转换
                    TableName = (a.TableName ?? "").ToLower(),
                    //MenuAuth = a.Auth,
                    UserAuth = a.Auth,
                    // 2022.03.26增移动端加菜单类型
                    MenuType = a.MenuType ?? 0
                }).ToList();
            return MenuActionToArray(permissions);
        }
        ICacheService cacheService = CacheService;
        string roleKey = roleId.GetRoleIdKey();

        //角色有缓存,并且当前服务器的角色版本号与redis/memory缓存角色的版本号相同直接返回静态对象角色权限
        string currnetVeriosn = "";
        if (rolePermissionsVersion.TryGetValue(roleId, out currnetVeriosn)
            && currnetVeriosn == cacheService.Get(roleKey))
        {
            return rolePermissions.ContainsKey(roleId) ? rolePermissions[roleId] : new List<Permissions>();
        }

        //锁定每个角色,通过安全字典减少锁粒度,否则多个同时角色获取缓存会导致阻塞
        object objId = objKeyValue.GetOrAdd(roleId.ToString(), new object());
        //锁定每个角色
        lock (objId)
        {
            if (rolePermissionsVersion.TryGetValue(roleId, out currnetVeriosn)
                && currnetVeriosn == cacheService.Get(roleKey))
            {
                return rolePermissions.ContainsKey(roleId) ? rolePermissions[roleId] : new List<Permissions>();
            }

            //没有redis/memory缓存角色的版本号或与当前服务器的角色版本号不同时,刷新缓存
            var dbContext = DBServerProvider.DbContext;
            List<Permissions> _permissions = (from a in dbContext.Set<Sys_Menu>()
                                              join b in dbContext.Set<Sys_RoleAuth>()
                                              on a.Menu_Id equals b.Menu_Id
                                              where b.Role_Id == roleId //&& a.ParentId > 0
                                              && b.AuthValue != ""
                                              orderby a.ParentId
                                              select new Permissions
                                              {
                                                  Menu_Id = a.Menu_Id,
                                                  ParentId = a.ParentId,
                                                  //2020.05.06增加默认将表名转换成小写,权限验证时不再转换
                                                  TableName = (a.TableName ?? "").ToLower(),
                                                  MenuAuth = a.Auth,
                                                  UserAuth = b.AuthValue ?? "",
                                                  // 2022.03.26增移动端加菜单类型
                                                  MenuType = a.MenuType ?? 0
                                              }).ToList();
            ActionToArray(_permissions);
            string _version = cacheService.Get(roleKey);
            //生成一个唯一版本号标识
            if (_version == null)
            {
                _version = DateTime.Now.ToString("yyyyMMddHHMMssfff");
                //将版本号写入缓存
                cacheService.Add(roleKey, _version);
            }
            //刷新当前服务器角色的权限
            rolePermissions[roleId] = _permissions;

            //写入当前服务器的角色最新版本号
            rolePermissionsVersion[roleId] = _version;
            return _permissions;
        }

    }

    /// <summary>
    /// 判断是否有权限
    /// </summary>
    /// <param name="tableName"></param>
    /// <param name="authName"></param>
    /// <param name="roleId"></param>
    /// <returns></returns>
    public bool ExistsPermissions(string tableName, string authName, int roleId = 0)
    {
        if (roleId <= 0) roleId = RoleId;
        tableName = tableName.ToLower();
        return GetPermissions(roleId).Any(x => x.TableName == tableName && x.UserAuthArr.Contains(authName));
    }

    /// <summary>
    /// 判断是否有权限
    /// </summary>
    /// <param name="tableName"></param>
    /// <param name="authName"></param>
    /// <param name="roleId"></param>
    /// <returns></returns>
    public bool ExistsPermissions(string tableName, ActionPermissionOptions actionPermission, int roleId = 0)
    {
        return ExistsPermissions(tableName, actionPermission.ToString(), roleId);
    }
    public int UserId
    {
        get
        {
            return (Context.User.FindFirstValue(JwtRegisteredClaimNames.Jti)
                ?? Context.User.FindFirstValue(ClaimTypes.NameIdentifier)).GetInt();
        }
    }

    public string UserName
    {
        get { return UserInfo.UserName; }
    }

    public string UserTrueName
    {
        get { return UserInfo.UserTrueName; }
    }

    public string Token
    {
        get { return UserInfo.Token; }
    }

    public int RoleId
    {
        get { return UserInfo.Role_Id; }
    }

    public void LogOut(int userId)
    {
        CacheService.Remove(userId.GetUserIdKey());
    }
}

学新通

3.2.2 ActionObserver

ActionObserver记录Action执行的信息

public class ActionObserver
{
    //public ActionObserver(IHttpContextAccessor httpContextAccessor)
    //{
    //    this.RequestDate = DateTime.Now;
    //    this.HttpContext = httpContextAccessor.HttpContext;
    //}
    /// <summary>
    /// 记录action执行的开始时间
    /// </summary>
    public DateTime RequestDate { get; set; }

    /// <summary>
    /// 当前请求是否已经写过日志,防止手动与系统自动重复写日志
    /// </summary>
    public bool IsWrite { get; set; }

    public HttpContext HttpContext { get; }
}

学新通

3.2.3 ObjectModelValidatorState

ObjectModelValidatorState 对象模型校验服务

public class ObjectModelValidatorState
{
    public ObjectModelValidatorState()
    {
        this.Status = true;
    }

    public bool Status { get; set; }
    public bool HasModelContent { get; set; }
    public string Code { get; set; }
    public string Message { get; set; }
}
public class ObjectValidatorResult
{
    public ObjectValidatorResult()
    {

    }
    public ObjectValidatorResult(bool status)
    {
        this.Status = status;
    }
    public ObjectValidatorResult OK(string message)
    {
        this.Status = true;
        this.Message = message;
        return this;
    }
    public ObjectValidatorResult Error(string message)
    {
        this.Status = false;
        this.Message = message;
        return this;
    }
    public bool Status { get; set; }
    public string Message { get; set; }
}

学新通

其实在Autofac中还注入了数据库服务,下一章讲解。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfikgge
系列文章
更多 icon
同类精品
更多 icon
继续加载