/// <summary> /// 重写Invoke /// </summary> /// <param name="context"></param> /// <param name="next"></param> /// <returns></returns> public override async Task Invoke(AspectContext context, AspectDelegate next) { var config = context.ServiceProvider.GetService(typeof(IConfiguration)) as IConfiguration; var prefix = config["RedisPrefix:DistributedLock"]; if (string.IsNullOrWhiteSpace(prefix)) { throw new H_Exception("请配置分布式锁名称的前缀字符"); } using (var redisLock = RedisHelper.Lock(prefix + _lockName, _timeoutSeconds, _autoDelay)) { if (redisLock == null) { H_Log.Error("系统异常:开启Redis分布式锁失败"); throw new H_Exception("系统异常"); } //if (redisLock == null) throw new H_Exception("系统异常"); //开启分布式锁超时 //对象为null,不占资源 ,编译后的代码没有fianlly,不执行dispose()方法 //锁超时是什么意思呢?如果一个得到锁的线程在执行任务的过程中挂掉,来不及显式地释放锁,这块资源将会永远被锁住,别的线程再也别想进来。 //所以,setnx的key必须设置一个超时时间,以保证即使没有被显式释放,这把锁也要在一定时间后自动释放。 await next(context); } }
/// <summary> /// 控制器中的操作执行后调用此方法 再执行H_ResultFilter全局过滤器 /// </summary> /// <param name="context"></param> public override void OnActionExecuted(ActionExecutedContext context) { object result = null; //EmptyResult对应null if (context.Result is ObjectResult) { result = (context.Result as ObjectResult)?.Value; } else if (context.Result is JsonResult) { result = (context.Result as JsonResult)?.Value; } var userId = context.HttpContext.User.Claims.FirstOrDefault(x => x.Type == JwtRegisteredClaimNames.Sid)?.Value; var descriptor = context.ActionDescriptor as ControllerActionDescriptor; if (!descriptor.MethodInfo.CustomAttributes.Any(x => x.AttributeType == typeof(IgnoreExcutedLogAttribute))) { H_Log.Info(new LogNote { Location = HttpContext.Request.Path.Value, Data = result, TraceId = context.HttpContext.TraceIdentifier, UserId = userId, Extra = "响应结果" }); } base.OnActionExecuted(context); }
public async Task <LoginOutput> LoginByAccountPwd(LoginByAccountPwdInput input) { string ip = HttpContext.GetIp(); H_Log.Info(new LogNote() { Location = "LoginByAccountPwd", Data = input, TraceId = HttpContext.TraceIdentifier, IP = ip, Extra = "登录请求" }); var result = await _loginAppService.LoginByAccountPwd(input, ip); H_Log.Info(new LogNote() { Location = "LoginByAccountPwd", Data = result, TraceId = HttpContext.TraceIdentifier, IP = ip, Extra = "登录返回" }); return(result); }
//public IOptionsSnapshot<H_AppSettingsConfig> AppsettingsOptions { get; set; } //属性注入必须public IOptionsSnapshot修改即更新 和IConfiguration效果一样 热更新 /// <summary> /// 控制器中的操作执行之前调用此方法(先执行这个方法 再执行模型验证) /// </summary> /// <param name="context"></param> public override void OnActionExecuting(ActionExecutingContext context) { var userId = User.Claims.FirstOrDefault(x => x.Type == JwtRegisteredClaimNames.Sid)?.Value; //Security Identifiers安全标识符 var jti = User.Claims.FirstOrDefault(x => x.Type == JwtRegisteredClaimNames.Jti)?.Value; var ip = context.HttpContext.GetIp(); var servicesParams = context.ActionDescriptor.Parameters.Where(a => a.BindingInfo.BindingSource == BindingSource.Services).Select(a => a.Name); H_Log.Info(new LogNote { Location = context.HttpContext.Request.Path.Value, Data = servicesParams.Any() ? context.ActionArguments.Where(a => !servicesParams.Contains(a.Key)) : context.ActionArguments, TraceId = context.HttpContext.TraceIdentifier, UserId = userId, IP = ip, Extra = "请求信息" }); var cache = GetCacheUser(userId, jti); //if (ip != cache.Ip) throw new H_Exception("请重新登录", nameof(H_Error.E100004).GetErrorCode()); CheckAuth(context, cache.AuthNums); var currentUser = context.HttpContext.RequestServices.GetService(typeof(ICurrentUser)) as CurrentUser; currentUser = cache.Adapt(currentUser); if (currentUser.Id == 2) { var method = context.HttpContext.Request.Method.ToLower(); var isLogout = context.HttpContext.Request.Path.Value == "/CurrentUser/Logout"; if (!isLogout) { if (method.Equals("post") || method.Equals("put") || method.Equals("delete")) { throw new H_Exception("游客账户,无法进行数据操作"); } } } base.OnActionExecuting(context); }
//静态方法效率上要比实例化高,静态方法的缺点是不自动进行销毁,而实例化的则可以做销毁。 //静态方法和静态变量创建后始终使用同一块内存,而使用实例的方式会创建多个内存。 /// <summary> /// 异常处理,不会处理eventbus中的异常 /// </summary> /// <param name="context"></param> /// <returns></returns> private static async Task Invoke(HttpContext context) { context.Response.StatusCode = StatusCodes.Status200OK; context.Response.ContentType = "application/json"; var response = new H_Response { Success = false }; var ex = context.Features.Get <IExceptionHandlerFeature>().Error; if (ex is H_Exception exception) { response.ErrorCode = exception.Code; response.ErrorMsg = exception.Message; } else if (ex is AspectInvocationException aspectException) { response.ErrorMsg = aspectException.InnerException?.Message; } #if DEBUG //开发环境 能看具体错误 else { response.ErrorMsg = ex.Message; } #endif if (string.IsNullOrWhiteSpace(response.ErrorMsg)) { response.ErrorMsg = "系统异常"; } H_Log.Error(ex, new LogNote() { Location = context.Request.Path.Value, TraceId = context.TraceIdentifier, Extra = "系统异常信息" }); //异常信息,记录到日志中 var options = new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, //解决中文乱码 PropertyNamingPolicy = null //PropertyNamingPolicy = JsonNamingPolicy.CamelCase //开头字母小写 默认 }; await context.Response.WriteAsync(JsonSerializer.Serialize(response, options), Encoding.UTF8); }
/// <summary> /// 异常处理,不会处理eventbus中的异常 /// </summary> /// <param name="context"></param> public override void OnException(ExceptionContext context) { var ex = context.Exception; var response = new H_Response { Success = false }; if (ex is H_Exception exception) { response.ErrorCode = exception.Code; response.ErrorMsg = exception.Message; } else if (ex is AspectInvocationException aspectException) { response.ErrorMsg = aspectException.InnerException?.Message; } #if DEBUG //开发环境 能看具体错误 else { response.ErrorMsg = ex.Message; } #endif if (string.IsNullOrWhiteSpace(response.ErrorMsg)) { response.ErrorMsg = "系统异常"; } context.Result = new JsonResult(response); H_Log.Error(ex, new LogNote() { Location = context.HttpContext.Request.Path.Value, TraceId = context.HttpContext.TraceIdentifier, Extra = "系统异常信息" }); //异常信息,记录到日志中 base.OnException(context); //返回结果 不会经过ResultFilter }
/// <summary> /// 用于配置中间件,以构建请求处理流水线 /// </summary> /// <param name="app"></param> /// <param name="env"></param> /// <param name="appSettings"></param> /// <returns></returns> internal static IApplicationBuilder Configure(this IApplicationBuilder app, IHostEnvironment env, H_AppSettings appSettings) { #region DevEnvironment if (env.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint($"{appSettings.Swagger.Name}/swagger.json", appSettings.Swagger.Name); }); app.UseCors(x => x.AllowCredentials().AllowAnyMethod().AllowAnyHeader().WithOrigins(appSettings.CorsUrls)); } #endregion app.UseSerilogRequestLogging(); #region Nginx // Nginx 获取ip app.UseForwardedHeaders(new ForwardedHeadersOptions() { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }); #endregion #region 异常中间件 // app.UseExceptionMiddleware(); #endregion #region 文件信息 //使用默认文件夹wwwroot app.UseStaticFiles(); //文件访问权限 app.UseWhen(a => a.Request.Path.Value.Contains(appSettings.FilePath.ExportExcelPath) || a.Request.Path.Value.Contains("file_template"), b => b.UseMiddleware <StaticFileMiddleware>()); //创建文件夹,保存导出的excel文件 if (!Directory.Exists(appSettings.FilePath.ExportExcelPath)) { Directory.CreateDirectory(appSettings.FilePath.ExportExcelPath); } app.UseStaticFiles(new StaticFileOptions() { FileProvider = new PhysicalFileProvider(appSettings.FilePath.ExportExcelPath), RequestPath = appSettings.RequestPath.ExportExcel, ContentTypeProvider = new FileExtensionContentTypeProvider(new Dictionary <string, string> { { ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" } }) }); ////创建文件夹,保存头像文件 //if (!Directory.Exists(appSettings.FilePath.AvatarPath)) //{ // Directory.CreateDirectory(appSettings.FilePath.AvatarPath); //} //app.UseStaticFiles(new StaticFileOptions() //{ // FileProvider = new PhysicalFileProvider(appSettings.FilePath.AvatarPath), // RequestPath = appSettings.RequestPath.AvatarFile //}); #endregion #region 路由&权限 app.UseRouting(); //权限 .net core3.0需要放UseRouting后面 app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); #endregion var projectName = Process.GetCurrentProcess().ProcessName; //使用Zookeeper自动分配管理WorkerId,解决时间回退问题和自动分配问题 new IdHelperBootstrapper() .UseZookeeper(appSettings.ZookeeperUrl, 200, projectName) .Boot(); H_Log.Info($"SnowflakeIdInfo ---> WorkId:{IdHelper.WorkerId},WorkTime:{DateTime.Now}"); return(app); }