文章目录

  • 前言
  • 一、Autofac的使用
    • 1.安装包
    • 2.服务注入
    • 3.AddModule扩展方法详解
      • 3.1 AppSetting.Init
        • 3.1.1 数据库字符串加/解密
      • 3.2 Autofac相关服务类
        • 3.2.1 UserContext
        • 3.2.2 ActionObserver
        • 3.2.3 ObjectModelValidatorState

前言

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=trueservices.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增加部门idDeptId = 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_Idwhere b.Role_Id == roleId //&& a.ParentId > 0&& b.AuthValue != ""orderby a.ParentIdselect 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中还注入了数据库服务,下一章讲解。

【愚公系列】2023年03月 MES生产制造执行系统-001.Autofac的使用相关推荐

  1. 【愚公系列】2023年03月 MES生产制造执行系统-002.Dapper和EFCode的使用

    文章目录 前言 1.Dapper 2.EF 一.Dapper和EFCode的使用的使用 1.数据库相关服务注入 1.1 DBServerProvider 1.2 Dapper的使用 1.3 EFCod ...

  2. 什么是MES生产制造执行系统?实施MES生产管理系统有哪些目标?

    一.什么是MES生产制造执行管理系统? MES系统通过控制包括物料.设备.人员.流程指令和设施在内的所有工厂资源,优化从定单到产品完成的整个生产活动,以最少的投入生产出最优的产品,实现连续均衡生产.M ...

  3. 什么是MES生产制造执行系统?实施系统有哪些好处?

    制造企业关心三个问题:生产什么?生产多少?如何生产? 企业的生产计划回答了前两个问题.""如何生产"由生产现场的过程控制系统SFC"掌握".ERP.C ...

  4. springBoot开源MES生产制造执行系统源码带文字搭建教程

    源码分享!需要源码学习参考可私信. 技术框架:springBoot + mybatis-plus  + shiro + hutool + layui + swagger + freemarker + ...

  5. 服装家纺生产制造执行系统——MES

    随着人们生活水平的提高,对服装的需求更趋向个性化,快时尚已经成为服装行业的主要业态.与此相适应,服装生产企业也逐步围绕"小批量.多品种.快速反应"的目标进行生产组织模式革新.作为劳 ...

  6. 什么是MES生产管理和生产制造执行系统?有哪些系统模块组成?

    文章目录 一.什么叫MES生产制造执行系统? 二.MES生产管理子系统有哪些? 1.APS高级计划排程系统 2.PLM产品研发管理系统 3.WMS仓库管理系统 4.SCM供应链管理系统 5.SRM供应 ...

  7. 服装行业智能生产制造执行系统(MES)——RFID技术的应用

    "物联网概念"是在"互联网概念"的基础上,将其用户端延伸和扩展到任何物品与物品之间,进行信息交换和通信的一种网络概念.其定义是:通过射频识别(RFID)红外感应 ...

  8. 【愚公系列】2022年01月 华为鸿蒙OS-03-四种模式开发实操

    文章目录 前言 一.使用JS语言开发(传统代码方式) 1.index页面源码 2.details页面源码 二.使用JS语言开发(低代码方式) 1.新建工程:注意选择 2.选择低代码新建页面 3.页面分 ...

  9. 2023年03月编程语言流行度排名

    点击查看最新编程语言流行度排名(每月更新) 2023年03月编程语言流行度排名 编程语言流行度排名是通过分析在谷歌上搜索语言教程的频率而创建的 一门语言教程被搜索的次数越多,大家就会认为该语言越受欢迎 ...

最新文章

  1. [原创]IrrLicht的GUI使用
  2. 浏览器是如何工作的?(转载)
  3. 如果央行加息,以前办的房贷利息也会涨吗?
  4. 推翻自己和过往,重学自定义View
  5. php菜单管理样式模板,php – SilverStripe Fluent菜单模板
  6. springboot+aop+自定义注解,打造通用的全局异常处理和参数校验切面(通用版)...
  7. Linux 常用命令 tar 打包文件夹
  8. 照片webp格式怎么改成jpg?
  9. 网络协议(一) TCP/IP 协议
  10. linux系统取消自检,Linux 磁盘自检设置
  11. Levenshtein Distance编辑距离应用实践——拼写检查(Java fork/join框架实现)
  12. 小白的python学习之路-turtle画不同大小的五角星
  13. MT 202 COV General Financial Institution Transfer 覆盖一般金融机构转账
  14. java小游戏------Flappy Bird(飞翔的小鸟含源码)
  15. onedrive php接口,Onedrive不用API,只用共享链接就能做成分享网盘
  16. 数据分析案例-基于PCA主成分分析法对葡萄酒数据进行分析
  17. 硬盘安装arch linux,ArchLinux硬盘安装
  18. python应用——习题练习
  19. 2021-2027全球与中国梨花油市场现状及未来发展趋势
  20. MySQL 数据类型(摘自菜鸟教程)

热门文章

  1. 如何学习电气自动化plc?
  2. 新东西013--Android软键盘详解
  3. 一、软考·系统架构师——计算机基础
  4. BZOJ4012 [HNOI2015]开店 (动态点分治)
  5. 加密货币借贷的危机时刻 |链捕手
  6. BZOJ3670 NOI2014 动物园 题解代码
  7. 你知道牛X哄哄帕斯卡计算器吗?
  8. Redis 最全面试题及答案
  9. cocos creator学习:PageView 控件的使用
  10. EtherCAT运动控制卡开发教程之python