Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8

IRC_NewDev
he 2024-10-17 10:14:52 +08:00
commit 5745161142
42 changed files with 672 additions and 620 deletions

View File

@ -77,7 +77,7 @@ namespace IRaCIS.Core.Application.Service.BusinessFilter
else if(statusCode != 200&&!(objectResult.Value is IResponseOutput)) else if(statusCode != 200&&!(objectResult.Value is IResponseOutput))
{ {
//---程序错误,请联系开发人员。 //---程序错误,请联系开发人员。
var apiResponse = ResponseOutput.NotOk(StaticData.International("UnifiedAPI_ProgramError")); var apiResponse = ResponseOutput.NotOk(I18n.T("UnifiedAPI_ProgramError"));
objectResult.Value = apiResponse; objectResult.Value = apiResponse;
objectResult.DeclaredType = apiResponse.GetType(); objectResult.DeclaredType = apiResponse.GetType();

View File

@ -18,6 +18,8 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.StaticFiles; using Microsoft.AspNetCore.StaticFiles;
using Microsoft.AspNetCore.WebUtilities; using Microsoft.AspNetCore.WebUtilities;
@ -43,6 +45,28 @@ namespace IRaCIS.Core.API.Controllers
#region 上传基类封装 #region 上传基类封装
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
var factories = context.ValueProviderFactories;
//factories.RemoveType<FormValueProviderFactory>();
factories.RemoveType<FormFileValueProviderFactory>();
factories.RemoveType<JQueryFormValueProviderFactory>();
context.HttpContext.Request.EnableBuffering();
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
}
}
[DisableFormValueModelBinding] [DisableFormValueModelBinding]
public abstract class UploadBaseController : ControllerBase public abstract class UploadBaseController : ControllerBase
{ {

View File

@ -17,6 +17,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Localization;
using Newtonsoft.Json; using Newtonsoft.Json;
using Serilog; using Serilog;
using System; using System;
@ -62,14 +63,6 @@ builder.Configuration.AddJsonFile(ConfigMapFileProvider.FromRelativePath(""), "a
builder.Host.UseSerilog(); builder.Host.UseSerilog();
#region Autofac 废弃
//builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
// .ConfigureContainer<ContainerBuilder>(containerBuilder =>
// {
// containerBuilder.RegisterModule<AutofacModuleSetup>();
// }).UseWindowsService();
#endregion
#endregion #endregion
@ -79,8 +72,8 @@ var _configuration = builder.Configuration;
//手动注册服务 //手动注册服务
builder.Services.ConfigureServices(_configuration); builder.Services.ConfigureServices(_configuration);
//异常处理 //minimal api 异常处理
//builder.Services.AddExceptionHandler<GlobalExceptionHandler>(); builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
//builder.Services.AddProblemDetails(); //builder.Services.AddProblemDetails();
//健康检查 //健康检查
@ -91,7 +84,6 @@ builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resourc
// 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim() // 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim()
builder.Services.AddControllers(options => builder.Services.AddControllers(options =>
{ {
//options.Filters.Add<LogActionFilter>();
options.Filters.Add<ModelActionFilter>(); options.Filters.Add<ModelActionFilter>();
options.Filters.Add<ProjectExceptionFilter>(); options.Filters.Add<ProjectExceptionFilter>();
options.Filters.Add<UnitOfWorkFilter>(); options.Filters.Add<UnitOfWorkFilter>();
@ -148,7 +140,11 @@ builder.Services.AddMasaMinimalAPIs(options =>
options.DeletePrefixes = new List<string> { "Delete", "Remove" }; options.DeletePrefixes = new List<string> { "Delete", "Remove" };
options.RouteHandlerBuilder= t=> { options.RouteHandlerBuilder= t=> {
t.RequireAuthorization().AddEndpointFilter<UnifiedApiResultEndpointFilter>().WithGroupName("Institution"); t.RequireAuthorization()
.AddEndpointFilter<LimitUserRequestAuthorizationEndpointFilter>()
.AddEndpointFilter<ModelValidationEndpointFilter>()
.AddEndpointFilter<UnifiedApiResultEndpointFilter>()
.WithGroupName("Institution");
}; };
options.DisableTrimMethodPrefix = true; //禁用去除方法前缀 options.DisableTrimMethodPrefix = true; //禁用去除方法前缀
options.DisableAutoMapRoute = false;//可通过配置true禁用全局自动路由映射或者删除此配置以启用全局自动路由映射 options.DisableAutoMapRoute = false;//可通过配置true禁用全局自动路由映射或者删除此配置以启用全局自动路由映射
@ -186,28 +182,8 @@ app.UseStatusCodePages(async context =>
}); });
//app.UseExceptionHandler(o => { }); //app.UseExceptionHandler();
app.UseExceptionHandler(o => { });
//这里没生效原因未知官方文档也是这种写法也用了GlobalExceptionHandler 尝试还是不行怀疑框架bug
//app.UseExceptionHandler(configure =>
//{
// configure.Run(async context =>
// {
// var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
//var ex = exceptionHandlerPathFeature?.Error;
//context.Response.ContentType = "application/json";
//if (ex != null)
//{
// var errorInfo = $"Exception: {ex.Message}[{ex.StackTrace}]" + (ex.InnerException != null ? $" InnerException: {ex.InnerException.Message}[{ex.InnerException.StackTrace}]" : "");
// await context.Response.WriteAsync(JsonConvert.SerializeObject(ResponseOutput.NotOk($"{ex?.Message}")));
// Log.Logger.Error(errorInfo);
//}
// });
//});
#region 暂时废弃 #region 暂时废弃
@ -272,10 +248,16 @@ app.MapMasaMinimalAPIs();
// Serilog // Serilog
SerilogExtension.AddSerilogSetup(enviromentName, app.Services); SerilogExtension.AddSerilogSetup(enviromentName, app.Services);
//设置国际化I18n
var localizer = app.Services.GetRequiredService<IStringLocalizer>();
I18n.SetLocalizer(localizer);
var hangfireJobService = app.Services.GetRequiredService<IIRaCISHangfireJob>(); var hangfireJobService = app.Services.GetRequiredService<IIRaCISHangfireJob>();
await hangfireJobService.InitHangfireJobTaskAsync(); await hangfireJobService.InitHangfireJobTaskAsync();
try try
{ {
#region 运行环境 部署平台 #region 运行环境 部署平台

View File

@ -1,7 +1,10 @@
using Hangfire; using Hangfire;
using Hangfire.Storage; using Hangfire.Storage;
using IRaCIS.Core.Application.Helper; using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Domain.Share;
using MassTransit;
using MassTransit.Scheduling;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace IRaCIS.Core.Application.Service.BackGroundJob namespace IRaCIS.Core.Application.Service.BackGroundJob
@ -9,15 +12,13 @@ namespace IRaCIS.Core.Application.Service.BackGroundJob
public interface IIRaCISHangfireJob public interface IIRaCISHangfireJob
{ {
//Task MemoryCacheTrialStatusAsync();
Task InitHangfireJobTaskAsync(); Task InitHangfireJobTaskAsync();
} }
public class IRaCISCHangfireJob(ILogger<IRaCISCHangfireJob> _logger, public class IRaCISCHangfireJob(ILogger<IRaCISCHangfireJob> _logger,
IRepository<Internationalization> _internationalizationRepository, IRepository<Internationalization> _internationalizationRepository,
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository,
IMessageScheduler _IMessageScheduler
) : IIRaCISHangfireJob ) : IIRaCISHangfireJob
{ {
public static string JsonFileFolder = Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources); public static string JsonFileFolder = Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources);
@ -29,43 +30,29 @@ namespace IRaCIS.Core.Application.Service.BackGroundJob
//初始化国际化 //初始化国际化
await InternationalizationHelper.InitInternationlizationDataAndWatchJsonFileAsync(_internationalizationRepository); //查询数据库的数据
var toJsonList = await _internationalizationRepository.Where(t => t.InternationalizationType == 1).Select(t => new IRCGlobalInfoDTO()
{
Code = t.Code,
Value = t.Value,
ValueCN = t.ValueCN,
Description = t.Description
}).ToListAsync();
await InternationalizationHelper.BatchAddJsonKeyValueAsync(toJsonList);
//创建邮件定时任务 //创建邮件定时任务
await InitSysAndTrialCronJobAsync(); await InitSysAndTrialCronJobAsync();
#region 废弃
////项目状态 立即加载到缓存中
//await MemoryCacheTrialStatusAsync();
////await MemoryCacheAnonymizeData();
////创建项目缓存 定时任务
//HangfireJobHelper.AddOrUpdateInitCronJob<IIRaCISHangfireJob>("RecurringJob_Cache_TrialState", t => t.MemoryCacheTrialStatusAsync(), Cron.Daily());
#endregion
_logger.LogInformation("项目启动 hangfire 任务初始化 执行结束"); _logger.LogInformation("项目启动 hangfire 任务初始化 执行结束");
} }
public async Task InitSysAndTrialCronJobAsync() public async Task InitSysAndTrialCronJobAsync()
{ {
//var deleteJobIdList = await _trialEmailNoticeConfigRepository.Where(t => t.Trial.TrialStatusStr != StaticData.TrialState.TrialOngoing && t.EmailCron != string.Empty && t.IsAutoSend)
// .Select(t => t.TrialId + "_" + t.Id)
// .ToListAsync();
//foreach (var jobId in deleteJobIdList)
//{
// HangfireJobHelper.RemoveCronJob(jobId);
//}
var taskInfoList = await _trialEmailNoticeConfigRepository.Where(t => t.Trial.TrialStatusStr == StaticData.TrialState.TrialOngoing && t.EmailCron != string.Empty && t.IsAutoSend) var taskInfoList = await _trialEmailNoticeConfigRepository.Where(t => t.Trial.TrialStatusStr == StaticData.TrialState.TrialOngoing && t.EmailCron != string.Empty && t.IsAutoSend)
.Select(t => new { t.Id, t.Code, t.EmailCron, t.BusinessScenarioEnum, t.TrialId }) .Select(t => new { t.Id, t.Code, t.EmailCron, t.BusinessScenarioEnum, t.TrialId })
@ -76,24 +63,29 @@ namespace IRaCIS.Core.Application.Service.BackGroundJob
//利用主键作为任务Id //利用主键作为任务Id
var jobId = $"{task.TrialId}_{task.Id}"; var jobId = $"{task.TrialId}_{task.Id}";
switch (task.BusinessScenarioEnum)
{
case EmailBusinessScenario.QCTask:
break;
case EmailBusinessScenario.CRCToQCQuestion:
break;
case EmailBusinessScenario.QCToCRCImageQuestion:
break;
default:
break;
}
HangfireJobHelper.AddOrUpdateTrialCronJob(jobId, task.TrialId, task.BusinessScenarioEnum, task.EmailCron); HangfireJobHelper.AddOrUpdateTrialCronJob(jobId, task.TrialId, task.BusinessScenarioEnum, task.EmailCron);
} }
var addOrUpdateJobIdList = taskInfoList.Select(t => $"{t.TrialId}_{t.Id}").ToList();
var list = JobStorage.Current.GetConnection().GetRecurringJobs().ToList();
//项目定时任务都在default 队列
//var dbJobIdList = JobStorage.Current.GetConnection().GetRecurringJobs().Where(t => t.Queue == "default").Select(t => t.Id).ToList();
//var deleteList= dbJobIdList.Except(addOrUpdateJobIdList).ToList();
// foreach (var jobId in deleteList)
// {
// HangfireJobHelper.RemoveCronJob(jobId);
// }
} }

View File

@ -1,43 +0,0 @@
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
namespace IRaCIS.Core.Application.BusinessFilter;
/// <summary>
/// 不生效,不知道为啥
/// </summary>
public class GlobalExceptionHandler : IExceptionHandler
{
private readonly ILogger<GlobalExceptionHandler> _logger;
public GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger)
{
this._logger = logger;
}
public ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
httpContext.Response.ContentType = "application/json";
var ex = exception;
var errorInfo = $"Exception: {ex.Message}[{ex.StackTrace}]" + (ex.InnerException != null ? $" InnerException: {ex.InnerException.Message}[{ex.InnerException.StackTrace}]" : "");
httpContext.Response.WriteAsJsonAsync(ResponseOutput.NotOk($"{ex?.Message}"));
_logger.LogError(errorInfo);
// return true to signal that this exception is handled
return ValueTask.FromResult(false);
}
}

View File

@ -13,24 +13,10 @@ namespace IRaCIS.Core.Application.Filter;
public class LimitUserRequestAuthorization : IAsyncAuthorizationFilter public class LimitUserRequestAuthorization(
IFusionCache _fusionCache, IUserInfo _userInfo, IStringLocalizer _localizer,
IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig) : IAsyncAuthorizationFilter
{ {
public IStringLocalizer _localizer { get; set; }
private readonly IFusionCache _fusionCache;
private readonly IUserInfo _userInfo;
private readonly IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig;
public LimitUserRequestAuthorization(IFusionCache fusionCache, IUserInfo userInfo, IStringLocalizer localizer, IOptionsMonitor<ServiceVerifyConfigOption> verifyConfig)
{
_fusionCache = fusionCache;
_userInfo = userInfo;
_verifyConfig = verifyConfig;
_localizer = localizer;
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext context) public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{ {

View File

@ -8,13 +8,9 @@ namespace IRaCIS.Core.Application.Filter;
public class ModelActionFilter : ActionFilterAttribute, IActionFilter public class ModelActionFilter(IStringLocalizer _localizer) : ActionFilterAttribute, IActionFilter
{ {
public IStringLocalizer _localizer;
public ModelActionFilter(IStringLocalizer localizer)
{
_localizer = localizer;
}
public override void OnActionExecuting(ActionExecutingContext context) public override void OnActionExecuting(ActionExecutingContext context)
{ {

View File

@ -0,0 +1,66 @@
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
namespace IRaCIS.Core.Application.Filter;
public class ProjectExceptionFilter(ILogger<ProjectExceptionFilter> _logger, IStringLocalizer _localizer) : Attribute, IExceptionFilter
{
public void OnException(ExceptionContext context)
{
//context.ExceptionHandled;//记录当前这个异常是否已经被处理过了
var exception = context.Exception;
if (!context.ExceptionHandled)
{
if (exception.GetType().Name == "DbUpdateConcurrencyException")
{
//---并发更新,当前不允许该操作
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["ProjectException_ConcurrentUpdateNotAllowed"] + exception.Message));
}
if (exception.GetType() == typeof(BusinessValidationFailedException))
{
var error = exception as BusinessValidationFailedException;
var info = string.Empty;
if (!string.IsNullOrWhiteSpace(error!.LocalizedKey) && StaticData.Localizer_Dev_Dic.ContainsKey(error!.LocalizedKey))
{
info = $"[{error!.LocalizedKey}]:{StaticData.Localizer_Dev_Dic[error!.LocalizedKey]}";
}
context.Result = new JsonResult(ResponseOutput.NotOk(exception.Message, "", error!.Code, localizedInfo: info));
}
else if (exception.GetType() == typeof(QueryBusinessObjectNotExistException))
{
context.Result = new JsonResult(ResponseOutput.NotOk(exception.Message, ApiResponseCodeEnum.DataNotExist));
}
else
{
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["Project_ExceptionContactDeveloper"] + (exception.InnerException is null ? (exception.Message)
: (exception.InnerException?.Message )), ApiResponseCodeEnum.ProgramException));
}
context.ExceptionHandled = true;//标记当前异常已经被处理过了
var errorInfo = $"Exception: {exception.Message}[{exception.StackTrace}]" + (exception.InnerException != null ? $" InnerException: {exception.InnerException.Message}[{exception.InnerException.StackTrace}]" : "");
_logger.LogError(errorInfo);
}
else
{
//继续
}
}
}

View File

@ -83,7 +83,7 @@ public class UnifiedApiResultFilter : Attribute, IAsyncResultFilter
else if (statusCode != 200 && !(objectResult.Value is IResponseOutput)) else if (statusCode != 200 && !(objectResult.Value is IResponseOutput))
{ {
//---程序错误,请联系开发人员。 //---程序错误,请联系开发人员。
var apiResponse = ResponseOutput.NotOk(StaticData.International("UnifiedAPI_ProgramError")); var apiResponse = ResponseOutput.NotOk(I18n.T("UnifiedAPI_ProgramError"));
objectResult.Value = apiResponse; objectResult.Value = apiResponse;
objectResult.DeclaredType = apiResponse.GetType(); objectResult.DeclaredType = apiResponse.GetType();

View File

@ -0,0 +1,73 @@
using DocumentFormat.OpenXml.InkML;
using IRaCIS.Core.Infrastructure;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace IRaCIS.Core.Application.BusinessFilter;
/// <summary>
/// minimal api 生效,但是传统控制器,没生效
/// 参考处理链接: https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/error-handling?view=aspnetcore-8.0
/// </summary>
public class GlobalExceptionHandler(IStringLocalizer _localizer, ILogger<GlobalExceptionHandler> _logger) : IExceptionHandler
{
public ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
httpContext.Response.StatusCode =StatusCodes.Status200OK;
httpContext.Response.ContentType = "application/json";
if (exception.GetType().Name == "DbUpdateConcurrencyException")
{
//---并发更新,当前不允许该操作
httpContext.Response.WriteAsJsonAsync(ResponseOutput.NotOk(_localizer["ProjectException_ConcurrentUpdateNotAllowed"] + exception.Message));
}
if (exception.GetType() == typeof(BusinessValidationFailedException))
{
var error = exception as BusinessValidationFailedException;
var info = string.Empty;
if (!string.IsNullOrWhiteSpace(error!.LocalizedKey) && StaticData.Localizer_Dev_Dic.ContainsKey(error!.LocalizedKey))
{
info = $"[{error!.LocalizedKey}]:{StaticData.Localizer_Dev_Dic[error!.LocalizedKey]}";
}
httpContext.Response.WriteAsJsonAsync(ResponseOutput.NotOk(exception.Message, "", error!.Code, localizedInfo: info));
//warning 级别记录
//_logger.LogWarning($"[{error!.LocalizedKey}]:{StaticData.Log_Locoalize_Dic[error!.LocalizedKey]}");
}
else if (exception.GetType() == typeof(QueryBusinessObjectNotExistException))
{
httpContext.Response.WriteAsJsonAsync(ResponseOutput.NotOk(exception.Message, ApiResponseCodeEnum.DataNotExist));
}
else
{
httpContext.Response.WriteAsJsonAsync(ResponseOutput.NotOk(_localizer["Project_ExceptionContactDeveloper"] + (exception.InnerException is null ? (exception.Message )
: (exception.InnerException?.Message)), ApiResponseCodeEnum.ProgramException));
}
var errorInfo = $"Exception: {exception.Message}[{exception.StackTrace}]" + (exception.InnerException != null ? $" InnerException: {exception.InnerException.Message}[{exception.InnerException.StackTrace}]" : "");
_logger.LogError(errorInfo);
// Return false to continue with the default behavior
// - or - return true to signal that this exception is handled
return ValueTask.FromResult(false);
}
}

View File

@ -0,0 +1,85 @@
using IRaCIS.Core.Application.Helper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.Service.BusinessFilter;
#region minimalapi 流程
public class LimitUserRequestAuthorizationEndpointFilter(
IFusionCache _fusionCache, IUserInfo _userInfo, IStringLocalizer _localizer,
IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig) : IEndpointFilter
{
public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
{
var minutes = _verifyConfig.CurrentValue.AutoLoginOutMinutes;
if (_verifyConfig.CurrentValue.OpenLoginLimit)
{
// 如果此请求允许匿名访问,不进行处理
var endpoint = context.HttpContext.GetEndpoint();
if (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null)
{
return await next(context);
}
// 没有从请求中取到 token
if (string.IsNullOrWhiteSpace(_userInfo.UserToken))
{
context.HttpContext.Response.ContentType = "application/json";
return Results.Json(ResponseOutput.NotOk(_localizer["LimitUser_AuthTokenMissing"]), statusCode: StatusCodes.Status200OK);
}
// 获取缓存中的用户 token
var cacheUserToken = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserToken(_userInfo.Id));
// 缓存中没有取到 token
if (string.IsNullOrWhiteSpace(cacheUserToken))
{
// 设置当前用户最新 token
await _fusionCache.SetAsync(CacheKeys.UserToken(_userInfo.Id), _userInfo.UserToken, TimeSpan.FromDays(7));
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.Id), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
}
// 如果是同一个用户
else if (cacheUserToken == _userInfo.UserToken)
{
var cacheTime = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserAutoLoginOut(_userInfo.Id));
// 如果过期,自动登出
if (string.IsNullOrEmpty(cacheTime))
{
context.HttpContext.Response.ContentType = "application/json";
return Results.Json(ResponseOutput.NotOk(_localizer["LimitUser_AccountAuto_LoginOut"], ApiResponseCodeEnum.AutoLoginOut), statusCode: StatusCodes.Status403Forbidden);
}
else
{
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.Id), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
}
}
else
{
// 如果账户在其他地方已登录,当前用户被迫下线
context.HttpContext.Response.ContentType = "application/json";
return Results.Json(ResponseOutput.NotOk(_localizer["LimitUser_AccountLoggedInElsewhere"], ApiResponseCodeEnum.LoginInOtherPlace), statusCode: StatusCodes.Status403Forbidden);
}
}
// 如果通过授权,继续执行请求管道
return await next(context);
}
}
#endregion

View File

@ -0,0 +1,58 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.BusinessFilter;
public class ModelValidationEndpointFilter(IStringLocalizer _localizer) : IEndpointFilter
{
public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
{
var httpContext = context.HttpContext;
//// 1. 获取路由参数并验证
//foreach (var routeValue in httpContext.Request.RouteValues)
//{
// {
// return Results.BadRequest(new { ErrorMessage = $"Invalid format for {routeValue.Key}." });
// }
//}
//// 2. 获取查询参数并验证
//foreach (var queryValue in httpContext.Request.Query)
//{
// {
// return Results.BadRequest(new { ErrorMessage = $"Invalid format for {queryValue.Key}." });
// }
//}
// 获取请求中的模型参数
var model = context.Arguments.FirstOrDefault(a => a != null && a.GetType().IsClass);
// 仅当模型存在时执行验证
if (model != null)
{
var validationResults = new List<ValidationResult>();
var validationContext = new ValidationContext(model);
bool isValid = Validator.TryValidateObject(model, validationContext, validationResults, true);
if (!isValid)
{
var validationErrors = validationResults.Select(vr => vr.ErrorMessage).ToArray();
return Results.Json(new
{
ErrorMessage = _localizer["ModelAction_InvalidAPIParameter"],
Errors = validationErrors
}, statusCode: StatusCodes.Status400BadRequest);
}
}
// 验证通过,继续执行
return await next(context);
}
}

View File

@ -0,0 +1,17 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.BusinessFilter;
public class TrialGlobalLimitEndpointFilter : IEndpointFilter
{
public ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
{
throw new NotImplementedException();
}
}

View File

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -11,14 +12,8 @@ namespace IRaCIS.Core.Application.Service.BusinessFilter;
#region minimalapi 流程 #region minimalapi 流程
public class UnifiedApiResultEndpointFilter : IEndpointFilter public class UnifiedApiResultEndpointFilter(ILogger<UnifiedApiResultEndpointFilter> _logger) : IEndpointFilter
{ {
private readonly ILogger _logger;
public UnifiedApiResultEndpointFilter(ILogger<UnifiedApiResultFilter> logger)
{
_logger = logger;
}
public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next) public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
{ {
@ -37,8 +32,13 @@ public class UnifiedApiResultEndpointFilter : IEndpointFilter
return ResponseOutput.Ok(tuple.Item1, tuple.Item2); return ResponseOutput.Ok(tuple.Item1, tuple.Item2);
} }
if (result is IResponseOutput) if (result is IResponseOutput responseOutput)
{ {
if (!string.IsNullOrWhiteSpace(responseOutput.LocalizedInfo))
{
//统一在这里记录国际化的日志信息
_logger.LogWarning($"{responseOutput.LocalizedInfo}");
}
return result; return result;
} }

View File

@ -1,26 +0,0 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace IRaCIS.Core.Application.Filter;
#region snippet_DisableFormValueModelBindingAttribute
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
var factories = context.ValueProviderFactories;
//factories.RemoveType<FormValueProviderFactory>();
factories.RemoveType<FormFileValueProviderFactory>();
factories.RemoveType<JQueryFormValueProviderFactory>();
context.HttpContext.Request.EnableBuffering();
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
}
}
#endregion

View File

@ -1,75 +0,0 @@
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
namespace IRaCIS.Core.Application.Filter;
public class ProjectExceptionFilter : Attribute, IExceptionFilter
{
private readonly ILogger<ProjectExceptionFilter> _logger;
public IStringLocalizer _localizer;
public ProjectExceptionFilter(IStringLocalizer localizer, ILogger<ProjectExceptionFilter> logger)
{
_logger = logger;
_localizer = localizer;
}
public void OnException(ExceptionContext context)
{
//context.ExceptionHandled;//记录当前这个异常是否已经被处理过了
if (!context.ExceptionHandled)
{
if (context.Exception.GetType().Name == "DbUpdateConcurrencyException")
{
//---并发更新,当前不允许该操作
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["ProjectException_ConcurrentUpdateNotAllowed"] + context.Exception.Message));
}
if (context.Exception.GetType() == typeof(BusinessValidationFailedException))
{
var error = context.Exception as BusinessValidationFailedException;
var info = string.Empty;
if (!string.IsNullOrWhiteSpace(error!.LocalizedKey) && StaticData.Log_Locoalize_Dic.ContainsKey(error!.LocalizedKey))
{
info = $"[{error!.LocalizedKey}]:{StaticData.Log_Locoalize_Dic[error!.LocalizedKey]}";
}
context.Result = new JsonResult(ResponseOutput.NotOk(context.Exception.Message, "", error!.Code, localizedInfo: info));
//warning 级别记录
//_logger.LogWarning($"[{error!.LocalizedKey}]:{StaticData.Log_Locoalize_Dic[error!.LocalizedKey]}");
}
else if (context.Exception.GetType() == typeof(QueryBusinessObjectNotExistException))
{
context.Result = new JsonResult(ResponseOutput.NotOk(context.Exception.Message, ApiResponseCodeEnum.DataNotExist));
}
else
{
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["Project_ExceptionContactDeveloper"] + (context.Exception.InnerException is null ? (context.Exception.Message /*+ context.Exception.StackTrace*/)
: (context.Exception.InnerException?.Message /*+ context.Exception.InnerException?.StackTrace*/)), ApiResponseCodeEnum.ProgramException));
_logger.LogError(context.Exception.InnerException is null ? (context.Exception.Message + context.Exception.StackTrace) : (context.Exception.InnerException?.Message + context.Exception.InnerException?.StackTrace));
}
context.ExceptionHandled = true;//标记当前异常已经被处理过了
//throw new Exception("test-result-exceptioin");
}
else
{
//继续
}
}
}

View File

@ -135,7 +135,7 @@ public static class FileStoreHelper
if (doc == null) if (doc == null)
{ {
//---数据库没有找到对应的数据模板文件,请联系系统运维人员。 //---数据库没有找到对应的数据模板文件,请联系系统运维人员。
throw new BusinessValidationFailedException(StaticData.International("FileStore_TemplateFileNotFound")); throw new BusinessValidationFailedException(I18n.T("FileStore_TemplateFileNotFound"));
} }
var filePath = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, doc.Path); var filePath = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, doc.Path);
@ -143,7 +143,7 @@ public static class FileStoreHelper
if (!System.IO.File.Exists(filePath)) if (!System.IO.File.Exists(filePath))
{ {
//---数据模板文件存储路径上未找对应文件,请联系系统运维人员。 //---数据模板文件存储路径上未找对应文件,请联系系统运维人员。
throw new BusinessValidationFailedException(StaticData.International("FileStore_TemplateFileStoragePathInvalid")); throw new BusinessValidationFailedException(I18n.T("FileStore_TemplateFileStoragePathInvalid"));
} }
return (filePath, isEn_US ? doc.Name.Trim('/') : doc.NameCN.Trim('/')); return (filePath, isEn_US ? doc.Name.Trim('/') : doc.NameCN.Trim('/'));
@ -269,7 +269,7 @@ public static class FileStoreHelper
{ {
//---解析Json文件配置出现问题 //---解析Json文件配置出现问题
throw new BusinessValidationFailedException(StaticData.International("SysMon_JsonConfig") + e.Message); throw new BusinessValidationFailedException(I18n.T("SysMon_JsonConfig") + e.Message);
} }
//默认存储的路径 //默认存储的路径

View File

@ -64,10 +64,10 @@ namespace IRaCIS.Core.Application.Helper
case EmailBusinessScenario.QCTask: case EmailBusinessScenario.QCTask:
HangfireJobHelper.AddOrUpdateCronJob<IEmailSendService>(jobId, t => t.SendTrialImageQCTaskEmailAsync(trialId), emailCron); HangfireJobHelper.AddOrUpdateCronJob<IEmailSendService>(jobId, t => t.SendTrialImageQCTaskEmailAsync(trialId), emailCron);
break; break;
case EmailBusinessScenario.QCQuestion: case EmailBusinessScenario.CRCToQCQuestion:
HangfireJobHelper.AddOrUpdateCronJob<IEmailSendService>(jobId, t => t.SendTrialQCQuestionEmailAsync(trialId), emailCron); HangfireJobHelper.AddOrUpdateCronJob<IEmailSendService>(jobId, t => t.SendTrialQCQuestionEmailAsync(trialId), emailCron);
break; break;
case EmailBusinessScenario.ImageQuestion: case EmailBusinessScenario.QCToCRCImageQuestion:
HangfireJobHelper.AddOrUpdateCronJob<IEmailSendService>(jobId, t => t.SendTrialImageQuestionAsync(trialId), emailCron); HangfireJobHelper.AddOrUpdateCronJob<IEmailSendService>(jobId, t => t.SendTrialImageQuestionAsync(trialId), emailCron);
break; break;

View File

@ -4,201 +4,134 @@ using IRaCIS.Core.Infrastructure;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using SharpCompress.Common;
namespace IRaCIS.Core.Application.Helper; namespace IRaCIS.Core.Application.Helper;
public class IRCGlobalInfoDTO
{
public string Code { get; set; }
public string Value { get; set; }
public string ValueCN { get; set; }
public string Description { get; set; }
}
public static class InternationalizationHelper public static class InternationalizationHelper
{ {
public static string JsonFileFolder = Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources); public static string JsonFileFolder = Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources);
public static FileSystemWatcher FileSystemWatcher_US { get; set; } public static string USJsonPath = Path.Combine(JsonFileFolder, StaticData.En_US_Json);
public static FileSystemWatcher FileSystemWatcher_CN { get; set; } public static string CNJsonPath = Path.Combine(JsonFileFolder, StaticData.Zh_CN_Json);
private static void VerifyFolder() static InternationalizationHelper()
{ {
if (!Directory.Exists(JsonFileFolder) || if (!Directory.Exists(JsonFileFolder) ||
!Directory.GetFiles(JsonFileFolder).Any(filePath => Path.GetExtension(filePath).Equals(".json", StringComparison.OrdinalIgnoreCase))) !Directory.GetFiles(JsonFileFolder).Any(filePath => Path.GetExtension(filePath).Equals(".json", StringComparison.OrdinalIgnoreCase)) ||
!File.Exists(USJsonPath) || !File.Exists(CNJsonPath))
{ {
throw new BusinessValidationFailedException("国际化Json文件目录有误"); throw new BusinessValidationFailedException(I18n.T("IRaCISCHangfireJob_FileNotFound"));
} }
} }
public static async Task BatchAddJsonKeyValueAsync(List<BatchAddInternationalizationDto> batchAddDtos)
public static async Task BatchAddJsonKeyValueAsync(List<IRCGlobalInfoDTO> list)
{ {
VerifyFolder(); await StoreInfoToFileAsync(list);
}
var usJsonPath = Path.Combine(JsonFileFolder, StaticData.En_US_Json); public static async Task AddOrUpdateJsonKeyValueAsync(IRCGlobalInfoDTO info)
var cnJsonPath = Path.Combine(JsonFileFolder, StaticData.Zh_CN_Json); {
var list = new List<IRCGlobalInfoDTO>() { info };
await StoreInfoToFileAsync(list);
}
//更新json 文件 同时更新内存缓存的数据 public static async Task StoreInfoToFileAsync(List<IRCGlobalInfoDTO> list)
foreach (var filePath in new string[] { usJsonPath, cnJsonPath }) {
foreach (var filePath in new string[] { USJsonPath, CNJsonPath })
{ {
var json = await File.ReadAllTextAsync(filePath); var json = await File.ReadAllTextAsync(filePath);
JObject jsonObject = JObject.Parse(json, new JsonLoadSettings() { CommentHandling = CommentHandling.Load }); JObject jsonObject = JObject.Parse(json, new JsonLoadSettings() { CommentHandling = CommentHandling.Load });
// 添加或更新指定的键值对
if (filePath.Contains(StaticData.En_US_Json)) if (filePath.Contains(StaticData.En_US_Json))
{ {
foreach (var item in batchAddDtos) foreach (var tojsonItem in list)
{ {
jsonObject[item.Code] = item.Value; jsonObject[tojsonItem.Code] = tojsonItem.Value;
StaticData.En_US_Dic[item.Code] = item.Value;
//日志记录该信息方便自己人看, 返回给客户的是配置的 //日志记录该信息方便自己人看, 返回给客户的是配置的
StaticData.Log_Locoalize_Dic[item.Code] = item.Description; StaticData.Localizer_Dev_Dic[tojsonItem.Code] = tojsonItem.Description;
} }
} }
else else
{ {
foreach (var item in batchAddDtos) foreach (var tojsonItem in list)
{ {
jsonObject[item.Code] = item.Value; jsonObject[tojsonItem.Code] = tojsonItem.ValueCN;
StaticData.Zh_CN_Dic[item.Code] = item.Value;
} }
} }
await File.WriteAllTextAsync(filePath, jsonObject.ToString()); await File.WriteAllTextAsync(filePath, jsonObject.ToString());
} }
} }
public static async Task AddOrUpdateJsonKeyValueAsync(string key, string value, string valueCN, string description)
{
VerifyFolder();
var usJsonPath = Path.Combine(JsonFileFolder, StaticData.En_US_Json);
var cnJsonPath = Path.Combine(JsonFileFolder, StaticData.Zh_CN_Json);
//更新json 文件 同时更新内存缓存的数据 #region 监测Json文件变更 实时刷新数据 废弃
foreach (var filePath in new string[] { usJsonPath, cnJsonPath }) //FileSystemWatcher_US = new FileSystemWatcher
{ //{
var json = await File.ReadAllTextAsync(filePath); // Path = Path.GetDirectoryName(USJsonPath)!,
// NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size,
// Filter = Path.GetFileName(USJsonPath),
// EnableRaisingEvents = true,
JObject jsonObject = JObject.Parse(json, new JsonLoadSettings() { CommentHandling = CommentHandling.Load }); //};
//// 添加文件更改事件的处理程序
// 添加或更新指定的键值对 //FileSystemWatcher_US.Changed += (sender, e) => LoadJsonFile(StaticData.Folder.Resources + "\\" + StaticData.En_US_Json);
if (filePath.Contains(StaticData.En_US_Json))
{
jsonObject[key] = value;
StaticData.En_US_Dic[key] = value;
//日志记录该信息方便自己人看, 返回给客户的是配置的
StaticData.Log_Locoalize_Dic[key] = description;
}
else
{
jsonObject[key] = valueCN;
StaticData.Zh_CN_Dic[key] = valueCN;
}
await File.WriteAllTextAsync(filePath, jsonObject.ToString()); //FileSystemWatcher_CN = new FileSystemWatcher
//{
// Path = Path.GetDirectoryName(CNJsonPath)!,
// NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size,
// Filter = Path.GetFileName(CNJsonPath),
// EnableRaisingEvents = true,
} //};
//FileSystemWatcher_CN.Changed += (sender, e) => LoadJsonFile(StaticData.Folder.Resources + "\\" + StaticData.Zh_CN_Json);
}
public static async Task InitInternationlizationDataAndWatchJsonFileAsync(IRepository<Internationalization> _internationalizationRepository) //private static void LoadJsonFile(string filePath)
{ //{
//查询数据库的数据 // Console.WriteLine("刷新json内存数据");
var toJsonList = await _internationalizationRepository.Where(t => t.InternationalizationType == 1).Select(t => new // IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile(filePath, false, false);
{
t.Code,
t.Value,
t.ValueCN,
t.Description
}).ToListAsync();
//组织成json 文件 // IConfigurationRoot enConfiguration = builder.Build();
var usJsonPath = Path.Combine(JsonFileFolder, StaticData.En_US_Json); // foreach (IConfigurationSection section in enConfiguration.GetChildren())
var cnJsonPath = Path.Combine(JsonFileFolder, StaticData.Zh_CN_Json); // {
// if (filePath.Contains(StaticData.En_US_Json))
// {
// StaticData.En_US_Dic[section.Key] = section.Value;
// }
// else
// {
// StaticData.Zh_CN_Dic[section.Key] = section.Value;
// }
// }
//}
//本地静态文件国际化需要 #endregion
foreach (var tojsonItem in toJsonList)
{
StaticData.En_US_Dic[tojsonItem.Code] = tojsonItem.Value;
StaticData.Zh_CN_Dic[tojsonItem.Code] = tojsonItem.ValueCN;
//日志记录该信息方便自己人看, 返回给客户的是配置的
StaticData.Log_Locoalize_Dic[tojsonItem.Code] = tojsonItem.Description;
}
File.WriteAllText(usJsonPath, JsonConvert.SerializeObject(StaticData.En_US_Dic));
File.WriteAllText(cnJsonPath, JsonConvert.SerializeObject(StaticData.Zh_CN_Dic));
//监测Json文件变更 实时刷新数据
if (!File.Exists(usJsonPath) || !File.Exists(cnJsonPath))
{
throw new BusinessValidationFailedException(StaticData.International("IRaCISCHangfireJob_FileNotFound"));
}
// //监测Json文件变更 实时刷新数据
FileSystemWatcher_US = new FileSystemWatcher
{
Path = Path.GetDirectoryName(usJsonPath)!,
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size,
Filter = Path.GetFileName(usJsonPath),
EnableRaisingEvents = true,
};
// 添加文件更改事件的处理程序
FileSystemWatcher_US.Changed += (sender, e) => LoadJsonFile(StaticData.Folder.Resources + "\\" + StaticData.En_US_Json);
FileSystemWatcher_CN = new FileSystemWatcher
{
Path = Path.GetDirectoryName(cnJsonPath)!,
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size,
Filter = Path.GetFileName(cnJsonPath),
EnableRaisingEvents = true,
};
FileSystemWatcher_CN.Changed += (sender, e) => LoadJsonFile(StaticData.Folder.Resources + "\\" + StaticData.Zh_CN_Json);
}
private static void LoadJsonFile(string filePath)
{
Console.WriteLine("刷新json内存数据");
IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile(filePath, false, false);
IConfigurationRoot enConfiguration = builder.Build();
foreach (IConfigurationSection section in enConfiguration.GetChildren())
{
if (filePath.Contains(StaticData.En_US_Json))
{
StaticData.En_US_Dic[section.Key] = section.Value;
}
else
{
StaticData.Zh_CN_Dic[section.Key] = section.Value;
}
}
}

View File

@ -42,7 +42,7 @@ public static class SendEmailHelper
{ {
//---邮件发送失败,您进行的操作未能成功,请检查邮箱或联系维护人员 //---邮件发送失败,您进行的操作未能成功,请检查邮箱或联系维护人员
throw new Exception(StaticData.International("SendEmail_SendFail"), new Exception(ex.Message)); throw new Exception(I18n.T("SendEmail_SendFail"), new Exception(ex.Message));
} }
@ -82,7 +82,7 @@ public static class SendEmailHelper
if (sMTPEmailConfig.ToMailAddressList.Count == 0) if (sMTPEmailConfig.ToMailAddressList.Count == 0)
{ {
//---没有收件人 //---没有收件人
throw new ArgumentException(StaticData.International("SendEmail_NoRecipient")); throw new ArgumentException(I18n.T("SendEmail_NoRecipient"));
} }
else else
{ {

View File

@ -27,6 +27,7 @@
<ItemGroup> <ItemGroup>
<None Remove="IRaCIS.Core.Application.xml" /> <None Remove="IRaCIS.Core.Application.xml" />
<None Remove="Resources\en-US.json" /> <None Remove="Resources\en-US.json" />
<None Remove="Resources\zh-CN.json" />
<None Remove="Resources\zh_ch.json" /> <None Remove="Resources\zh_ch.json" />
<None Remove="Service\Allocation\TaskConsistentRuleService.cs~RF1603d47.TMP" /> <None Remove="Service\Allocation\TaskConsistentRuleService.cs~RF1603d47.TMP" />
<None Remove="Service\Reading\ReadingImageTask\ReadingImageTaskService.cs~RF2f9323.TMP" /> <None Remove="Service\Reading\ReadingImageTask\ReadingImageTaskService.cs~RF2f9323.TMP" />
@ -40,6 +41,9 @@
<ExcludeFromSingleFile>true</ExcludeFromSingleFile> <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content> </Content>
<Content Include="Resources\zh-CN.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -12747,7 +12747,14 @@
</member> </member>
<member name="T:IRaCIS.Core.Application.BusinessFilter.GlobalExceptionHandler"> <member name="T:IRaCIS.Core.Application.BusinessFilter.GlobalExceptionHandler">
<summary> <summary>
不生效,不知道为啥 minimal api 生效,但是传统控制器,没生效
参考处理链接: https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/error-handling?view=aspnetcore-8.0
</summary>
</member>
<member name="M:IRaCIS.Core.Application.BusinessFilter.GlobalExceptionHandler.#ctor(Microsoft.Extensions.Localization.IStringLocalizer,Microsoft.Extensions.Logging.ILogger{IRaCIS.Core.Application.BusinessFilter.GlobalExceptionHandler})">
<summary>
minimal api 生效,但是传统控制器,没生效
参考处理链接: https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/error-handling?view=aspnetcore-8.0
</summary> </summary>
</member> </member>
<member name="T:IRaCIS.Core.Application.Filter.TrialResourceFilter"> <member name="T:IRaCIS.Core.Application.Filter.TrialResourceFilter">
@ -12890,42 +12897,6 @@
构造函数注入 构造函数注入
</summary> </summary>
</member> </member>
<member name="T:IRaCIS.Core.Application.MassTransit.Consumer.AddSubjectTriggerConsumer">
<summary>
添加Subject 触发添加访视 不能代替 Trigger,稽查BatchId 不一致
因为消费者这里的数据库上下文 和消息发送者上下文不是同一个,相当于两个独立的事务
</summary>
<param name="_subjectVisitRepository"></param>
<param name="_visitStageRepository"></param>
<param name="_trialRepository"></param>
<param name="_mapper"></param>
</member>
<member name="M:IRaCIS.Core.Application.MassTransit.Consumer.AddSubjectTriggerConsumer.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectVisit},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitStage},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},AutoMapper.IMapper)">
<summary>
添加Subject 触发添加访视 不能代替 Trigger,稽查BatchId 不一致
因为消费者这里的数据库上下文 和消息发送者上下文不是同一个,相当于两个独立的事务
</summary>
<param name="_subjectVisitRepository"></param>
<param name="_visitStageRepository"></param>
<param name="_trialRepository"></param>
<param name="_mapper"></param>
</member>
<member name="T:IRaCIS.Core.Application.MassTransit.Consumer.MasstransitTestConsumer">
<summary>
meditor send 的时候,请求流会先到消费者,返回后才会执行后续代码
publish 请求流不会先到消费者,发布后,直接执行后续代码
</summary>
<param name="_userRepository"></param>
</member>
<member name="M:IRaCIS.Core.Application.MassTransit.Consumer.MasstransitTestConsumer.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.User})">
<summary>
meditor send 的时候,请求流会先到消费者,返回后才会执行后续代码
publish 请求流不会先到消费者,发布后,直接执行后续代码
</summary>
<param name="_userRepository"></param>
</member>
<member name="T:IRaCIS.Core.Application.MassTransit.Consumer.UrgentMedicalReviewAddedEventConsumer"> <member name="T:IRaCIS.Core.Application.MassTransit.Consumer.UrgentMedicalReviewAddedEventConsumer">
<summary> <summary>
加急的医学反馈任务 通知MIM 加急的医学反馈任务 通知MIM
@ -13014,11 +12985,42 @@
通知PM 进行一致性核查 通知PM 进行一致性核查
</summary> </summary>
</member> </member>
<member name="T:IRaCIS.Core.Application.MassTransit.Consumer.MasstransitTestConsumer">
<summary>
meditor send 的时候,请求流会先到消费者,返回后才会执行后续代码
publish 请求流不会先到消费者,发布后,直接执行后续代码
</summary>
<param name="_userRepository"></param>
</member>
<member name="M:IRaCIS.Core.Application.MassTransit.Consumer.MasstransitTestConsumer.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.User})">
<summary>
meditor send 的时候,请求流会先到消费者,返回后才会执行后续代码
publish 请求流不会先到消费者,发布后,直接执行后续代码
</summary>
<param name="_userRepository"></param>
</member>
<member name="T:IRaCIS.Core.Application.MassTransit.Consumer.MediatorHttpContextScopeFilterExtensions"> <member name="T:IRaCIS.Core.Application.MassTransit.Consumer.MediatorHttpContextScopeFilterExtensions">
<summary> <summary>
参考链接https://github.com/MassTransit/MassTransit/discussions/2498 参考链接https://github.com/MassTransit/MassTransit/discussions/2498
</summary> </summary>
</member> </member>
<member name="T:IRaCIS.Core.Application.MassTransit.Consumer.QCImageQuestionSchedule">
<summary>
QC 影像质疑待处理
</summary>
</member>
<member name="T:IRaCIS.Core.Application.MassTransit.Consumer.CRCImageQuestionSchedule">
<summary>
CRC 影像质疑
</summary>
</member>
<member name="T:IRaCIS.Core.Application.MassTransit.Consumer.ImageQCSchedule">
<summary>
影像质控
</summary>
</member>
<member name="T:IRaCIS.Core.Application.ViewModel.TaskAllocationRuleView"> <member name="T:IRaCIS.Core.Application.ViewModel.TaskAllocationRuleView">
<summary> TaskAllocationRuleView 列表视图模型 </summary> <summary> TaskAllocationRuleView 列表视图模型 </summary>
</member> </member>

View File

@ -1,101 +0,0 @@

using AutoMapper;
using IRaCIS.Core.Domain;
using MassTransit;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace IRaCIS.Core.Application.MassTransit.Consumer;
/// <summary>
/// 添加Subject 触发添加访视 不能代替 Trigger,稽查BatchId 不一致
/// 因为消费者这里的数据库上下文 和消息发送者上下文不是同一个,相当于两个独立的事务
/// </summary>
/// <param name="_subjectVisitRepository"></param>
/// <param name="_visitStageRepository"></param>
/// <param name="_trialRepository"></param>
/// <param name="_mapper"></param>
public class AddSubjectTriggerConsumer(IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<VisitStage> _visitStageRepository,
IRepository<Trial> _trialRepository,
IMapper _mapper) : IConsumer<AddSubjectTriggerCommand>
{
public async Task Consume(ConsumeContext<AddSubjectTriggerCommand> context)
{
var addSubjectEvent = context.Message;
{
Console.WriteLine(_visitStageRepository._dbContext.GetHashCode());
Console.WriteLine("两个 DbContext 不是同一个实例");
}
//添加受试者的时候,获取访视计划列表,添加到受试者访视表。
var visitPlanList = await _visitStageRepository.Where(t => t.TrialId == addSubjectEvent.TrialId && t.IsConfirmed).ToListAsync();
var svList = _mapper.Map<List<SubjectVisit>>(visitPlanList);
var IsEnrollementQualificationConfirm = await _trialRepository.Where(t => t.Id == addSubjectEvent.TrialId).Select(u => u.IsEnrollementQualificationConfirm).FirstOrDefaultAsync();
svList.ForEach(t =>
{
t.SubjectId = addSubjectEvent.SubjectId;
t.TrialId = addSubjectEvent.TrialId;
t.TrialSiteId = addSubjectEvent.TrialSiteId;
t.IsEnrollmentConfirm = t.IsBaseLine ? IsEnrollementQualificationConfirm : false;
t.Id = NewId.NextGuid();
});
await _subjectVisitRepository.AddRangeAsync(svList);
}
}
public class AddSubjectTriggerConsumer2(IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<VisitStage> _visitStageRepository,
IRepository<Trial> _trialRepository,
IMapper _mapper) : IConsumer<AddSubjectTriggerCommand2>
{
public async Task Consume(ConsumeContext<AddSubjectTriggerCommand2> context)
{
var addSubjectEvent = context.Message;
{
Console.WriteLine(_visitStageRepository._dbContext.GetHashCode());
Console.WriteLine("两个 DbContext 不是同一个实例");
}
//添加受试者的时候,获取访视计划列表,添加到受试者访视表。
var visitPlanList = await _visitStageRepository.Where(t => t.TrialId == addSubjectEvent.TrialId && t.IsConfirmed).ToListAsync();
var svList = _mapper.Map<List<SubjectVisit>>(visitPlanList);
var IsEnrollementQualificationConfirm = await _trialRepository.Where(t => t.Id == addSubjectEvent.TrialId).Select(u => u.IsEnrollementQualificationConfirm).FirstOrDefaultAsync();
svList.ForEach(t =>
{
t.SubjectId = addSubjectEvent.SubjectId;
t.TrialId = addSubjectEvent.TrialId;
t.TrialSiteId = addSubjectEvent.TrialSiteId;
t.IsEnrollmentConfirm = t.IsBaseLine ? IsEnrollementQualificationConfirm : false;
t.Id = NewId.NextGuid();
});
await _subjectVisitRepository.AddRangeAsync(svList);
}
}

View File

@ -54,6 +54,7 @@ public class TestMasstransitService : BaseService
{ {
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US; var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
Console.WriteLine(_testLengthRepository._dbContext.GetHashCode()); Console.WriteLine(_testLengthRepository._dbContext.GetHashCode());
//IScopedMediator 上下文一致, IMediator上下文不一致 //IScopedMediator 上下文一致, IMediator上下文不一致

View File

@ -0,0 +1,56 @@
using MassTransit;
using MassTransit.Scheduling;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.MassTransit.Consumer;
public abstract class IRCRecurringSchedule :
RecurringSchedule
{
protected IRCRecurringSchedule()
{
ScheduleGroup = GetType().Name;
TimeZoneId = TimeZoneInfo.Local.Id;
StartTime = DateTime.Now;
}
public MissedEventPolicy MisfirePolicy { get; protected set; }
public string TimeZoneId { get; protected set; }
public DateTimeOffset StartTime { get; protected set; }
public DateTimeOffset? EndTime { get; protected set; }
public string ScheduleId { get; private set; }
public string ScheduleGroup { get; private set; }
public string CronExpression { get; protected set; }
public string Description { get; protected set; }
}
/// <summary>
/// QC 影像质疑待处理
/// </summary>
public class QCImageQuestionSchedule : IRCRecurringSchedule
{
}
/// <summary>
/// CRC 影像质疑
/// </summary>
public class CRCImageQuestionSchedule : IRCRecurringSchedule
{
}
/// <summary>
/// 影像质控
/// </summary>
public class ImageQCSchedule : IRCRecurringSchedule
{
}

View File

@ -175,7 +175,7 @@ namespace IRaCIS.Core.Application.Service
if (addOrEditInternationalization.InternationalizationType == 1) if (addOrEditInternationalization.InternationalizationType == 1)
{ {
await InternationalizationHelper.AddOrUpdateJsonKeyValueAsync(entity.Code, addOrEditInternationalization.Value, addOrEditInternationalization.ValueCN, addOrEditInternationalization.Description); await InternationalizationHelper.AddOrUpdateJsonKeyValueAsync(_mapper.Map<IRCGlobalInfoDTO>(addOrEditInternationalization));
} }
else else
{ {

View File

@ -1,6 +1,7 @@
using AutoMapper; using AutoMapper;
using IRaCIS.Application.Contracts; using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Application.ViewModel;
namespace IRaCIS.Core.Application.Service namespace IRaCIS.Core.Application.Service
@ -70,6 +71,9 @@ namespace IRaCIS.Core.Application.Service
CreateMap<Internationalization, BatchInternationalizationDto>().ReverseMap(); CreateMap<Internationalization, BatchInternationalizationDto>().ReverseMap();
CreateMap<Internationalization, IRCGlobalInfoDTO>();
CreateMap<EventStoreRecord, EventStoreRecordView>();
CreateMap<BatchAddInternationalizationDto, InternationalizationAddOrEdit>(); CreateMap<BatchAddInternationalizationDto, InternationalizationAddOrEdit>();

View File

@ -203,7 +203,7 @@ namespace IRaCIS.Core.Application.Service
return (topicStr, htmlBodyStr, false, userId); return (topicStr, htmlBodyStr, false, userId);
}; };
await SendTrialEmailAsync(trialId, EmailBusinessScenario.QCQuestion, topicAndHtmlFunc); await SendTrialEmailAsync(trialId, EmailBusinessScenario.CRCToQCQuestion, topicAndHtmlFunc);
} }
} }
} }
@ -253,7 +253,7 @@ namespace IRaCIS.Core.Application.Service
return (topicStr, htmlBodyStr, isEn_us, userId); return (topicStr, htmlBodyStr, isEn_us, userId);
}; };
await SendTrialEmailAsync(trialId, EmailBusinessScenario.ImageQuestion, topicAndHtmlFunc); await SendTrialEmailAsync(trialId, EmailBusinessScenario.QCToCRCImageQuestion, topicAndHtmlFunc);
} }
} }
} }

View File

@ -397,7 +397,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
if (_fusionCache.GetOrDefault<Guid>(CacheKeys.TrialTaskStudyUidDBLock(incommand.TrialId, incommand.VisitTaskId, incommand.Study.StudyInstanceUid)) != Guid.Empty) if (_fusionCache.GetOrDefault<Guid>(CacheKeys.TrialTaskStudyUidDBLock(incommand.TrialId, incommand.VisitTaskId, incommand.Study.StudyInstanceUid)) != Guid.Empty)
{ {
//---当前已有人正在上传和归档该检查! //---当前已有人正在上传和归档该检查!
return ResponseOutput.NotOk(StaticData.International("UploadDownLoad_ArchiveInProgress")); return ResponseOutput.NotOk(I18n.T("UploadDownLoad_ArchiveInProgress"));
} }
else else
{ {

View File

@ -102,7 +102,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
if (cacheValue != Guid.Empty && cacheValue != _userInfo.Id) if (cacheValue != Guid.Empty && cacheValue != _userInfo.Id)
{ {
//---当前已有人正在上传和归档该检查! //---当前已有人正在上传和归档该检查!
return ResponseOutput.NotOk(StaticData.International("UploadDownLoad_ArchiveInProgress")); return ResponseOutput.NotOk(I18n.T("UploadDownLoad_ArchiveInProgress"));
} }
else else
{ {
@ -134,7 +134,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
if (_fusionCache.GetOrDefault<Guid>(CacheKeys.TrialStudyUidDBLock(incommand.TrialId, incommand.Study.StudyInstanceUid)) != Guid.Empty) if (_fusionCache.GetOrDefault<Guid>(CacheKeys.TrialStudyUidDBLock(incommand.TrialId, incommand.Study.StudyInstanceUid)) != Guid.Empty)
{ {
//---当前已有人正在上传和归档该检查! //---当前已有人正在上传和归档该检查!
return ResponseOutput.NotOk(StaticData.International("UploadDownLoad_ArchiveInProgress")); return ResponseOutput.NotOk(I18n.T("UploadDownLoad_ArchiveInProgress"));
} }
else else
{ {

View File

@ -28,7 +28,7 @@ using NPOI.XWPF.UserModel;
using System.Globalization; using System.Globalization;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using Tea;
namespace IRaCIS.Core.Application.Service namespace IRaCIS.Core.Application.Service
@ -56,10 +56,25 @@ namespace IRaCIS.Core.Application.Service
return Task.FromResult(list); return Task.FromResult(list);
} }
[AllowAnonymous]
public IResponseOutput GetTest() public IResponseOutput GetTest()
{ {
//throw new BusinessValidationFailedException("手动抛出的异常");
return ResponseOutput.Ok(_userInfo.IP); return ResponseOutput.Ok(_userInfo.IP);
} }
public IResponseOutput GetTestI18n()
{
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
//CultureInfo.CurrentCulture = new CultureInfo(StaticData.CultureInfo.en_US);
//CultureInfo.CurrentUICulture = new CultureInfo(StaticData.CultureInfo.en_US);
return ResponseOutput.Ok(I18n.T("TaskAllocation_DoctorConfigExists"));
}
} }
@ -167,6 +182,8 @@ namespace IRaCIS.Core.Application.Service
public async Task<IResponseOutput> TestJson() public async Task<IResponseOutput> TestJson()
{ {
throw new BusinessValidationFailedException("传统控制器异常");
var model1 = new TestModel() { TestId = NewId.NextSequentialGuid(), TestName = null }; var model1 = new TestModel() { TestId = NewId.NextSequentialGuid(), TestName = null };
var model2 = new TestModel2() { TestId = NewId.NextSequentialGuid(), TestName = "test2" }; var model2 = new TestModel2() { TestId = NewId.NextSequentialGuid(), TestName = "test2" };

View File

@ -46,11 +46,13 @@ namespace IRaCIS.Core.Domain.Share
//Reviewer=4, //Reviewer=4,
//QC影像质控任务
QCTask = 5, QCTask = 5,
QCQuestion = 6,
ImageQuestion = 7, CRCToQCQuestion = 6,
QCToCRCImageQuestion = 7,

View File

@ -4,3 +4,4 @@ global using System;
global using System.Collections.Generic; global using System.Collections.Generic;
global using System.ComponentModel.DataAnnotations; global using System.ComponentModel.DataAnnotations;
global using System.ComponentModel.DataAnnotations.Schema; global using System.ComponentModel.DataAnnotations.Schema;
global using IRaCIS.Core.Infrastructure.Extention;

View File

@ -62,7 +62,7 @@ public class ReadingQuestionCriterionTrial : BaseAddAuditEntity
[Comment("全局阅片评估更新类型")] [Comment("全局阅片评估更新类型")]
public string GlobalUpdateType { get; set; } = string.Empty; public string GlobalUpdateType { get; set; } = string.Empty;
[Comment("评估原因")] [Comment("评估原因")]
public string EvaluationReason { get; set; } = StaticData.International("CriterionTrial_EvaluationReason"); public string EvaluationReason { get; set; } = I18n.T("CriterionTrial_EvaluationReason");
[Comment("是否显示详情")] [Comment("是否显示详情")]
public bool IsShowDetail { get; set; } = true; public bool IsShowDetail { get; set; } = true;

View File

@ -132,7 +132,7 @@ public partial class Trial : BaseFullDeleteAuditEntity
public bool VisitPlanConfirmed { get; set; } public bool VisitPlanConfirmed { get; set; }
[Comment("受试者编号具体规则")] [Comment("受试者编号具体规则")]
public string SubjectCodeRule { get; set; } = StaticData.International("Trial_number"); public string SubjectCodeRule { get; set; } = I18n.T("Trial_number");
[Comment("是否 提醒受试者编号规则")] [Comment("是否 提醒受试者编号规则")]
public bool IsNoticeSubjectCodeRule { get; set; } = true; public bool IsNoticeSubjectCodeRule { get; set; } = true;

View File

@ -71,23 +71,9 @@ namespace IRaCIS.Core.Infra.EFCore
bool autoSave = false, bool ignoreQueryFilter = false) where T : Entity; bool autoSave = false, bool ignoreQueryFilter = false) where T : Entity;
} }
public class Repository : IRepository public class Repository(IRaCISDBContext _dbContext, IMapper _mapper, IUserInfo _userInfo) : IRepository
{ {
#region 构造 基本
private IRaCISDBContext _dbContext { get; }
public IMapper _mapper { get; set; }
public IUserInfo _userInfo { get; set; }
public IStringLocalizer _localizer { get; set; }
public Repository(IRaCISDBContext dbContext, IMapper mapper, IUserInfo userInfo, IStringLocalizer localizer)
{
_localizer = localizer;
_dbContext = dbContext;
_mapper = mapper;
_userInfo = userInfo;
}
/// <summary> /// <summary>
/// 设置是使用哪个仓储 默认不跟踪 /// 设置是使用哪个仓储 默认不跟踪
@ -171,7 +157,7 @@ namespace IRaCIS.Core.Infra.EFCore
if (dbEntity == null) if (dbEntity == null)
{ {
throw new BusinessValidationFailedException(_localizer["Repository_UpdateError"]); throw new BusinessValidationFailedException(I18n.T("Repository_UpdateError"));
} }
var dbBeforEntity = dbEntity.Clone(); var dbBeforEntity = dbEntity.Clone();
@ -450,7 +436,6 @@ namespace IRaCIS.Core.Infra.EFCore
} }
#endregion

View File

@ -100,7 +100,7 @@ namespace IRaCIS.Core.Infra.EFCore
if (dbEntity == null) if (dbEntity == null)
{ {
throw new BusinessValidationFailedException(_localizer["Repository_UpdateError"]); throw new BusinessValidationFailedException(I18n.T("Repository_UpdateError"));
} }
var dbBeforEntity = dbEntity.Clone(); var dbBeforEntity = dbEntity.Clone();
@ -156,7 +156,7 @@ namespace IRaCIS.Core.Infra.EFCore
if (searchEntity == null) if (searchEntity == null)
{ {
throw new BusinessValidationFailedException(_localizer["Repository_UpdateError"]); throw new BusinessValidationFailedException(I18n.T("Repository_UpdateError"));
} }
_dbContext.EntityModifyPartialFiled(searchEntity, updateFactory); _dbContext.EntityModifyPartialFiled(searchEntity, updateFactory);
@ -208,7 +208,7 @@ namespace IRaCIS.Core.Infra.EFCore
if (waitDelete == null) if (waitDelete == null)
{ {
throw new BusinessValidationFailedException(_localizer["Repository_DeleteError"]); throw new BusinessValidationFailedException(I18n.T("Repository_DeleteError"));
} }
await DeleteAsync(waitDelete, autoSave); await DeleteAsync(waitDelete, autoSave);

View File

@ -0,0 +1,31 @@
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Infrastructure.Extention;
public static class I18n
{
private static IStringLocalizer _localizer;
public static void SetLocalizer(IStringLocalizer localizer)
{
_localizer = localizer;
}
public static string T(string key)
{
return _localizer[key];
}
public static string T(string key, params object[] arguments)
{
return _localizer[key, arguments];
}
}

View File

@ -117,9 +117,9 @@ namespace IRaCIS.Core.Infrastructure.Extention
var info = string.Empty; var info = string.Empty;
if (!string.IsNullOrWhiteSpace(key) && StaticData.Log_Locoalize_Dic.ContainsKey(key)) if (!string.IsNullOrWhiteSpace(key) && StaticData.Localizer_Dev_Dic.ContainsKey(key))
{ {
info = $"[{key}]:{StaticData.Log_Locoalize_Dic[key]}"; info = $"[{key}]:{StaticData.Localizer_Dev_Dic[key]}";
} }
return new ResponseOutput<string>().NotOk(msg, code: code, localizedInfo: info); return new ResponseOutput<string>().NotOk(msg, code: code, localizedInfo: info);

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
@ -7,12 +8,7 @@ namespace IRaCIS.Core.Domain.Share;
public static class StaticData public static class StaticData
{ {
public static Dictionary<string, string> Localizer_Dev_Dic = new Dictionary<string, string>();
public static Dictionary<string, string> En_US_Dic = new Dictionary<string, string>();
public static Dictionary<string, string> Zh_CN_Dic = new Dictionary<string, string>();
public static Dictionary<string, string> Log_Locoalize_Dic = new Dictionary<string, string>();
#region 国际化 #region 国际化
@ -28,48 +24,34 @@ public static class StaticData
public static readonly string en_US_bookMark = "en_us"; public static readonly string en_US_bookMark = "en_us";
} }
/// <summary> #region 国际化废弃
/// 获取国际化
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static string International(string key, params object?[] args)
{
try
{
return string.Format(GetLanguageDictionary(key), args);
}
catch (Exception)
{
return string.Empty; //public static Dictionary<string, string> En_US_Dic = new Dictionary<string, string>();
}
} //public static Dictionary<string, string> Zh_CN_Dic = new Dictionary<string, string>();
///// <summary>
///// 获取国际化
///// </summary>
///// <param name="data"></param>
///// <returns></returns>
//public static string I18n(string key, params object?[] args)
//{
// var isEn_US = System.Globalization.CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
// if (isEn_US)
// {
// return En_US_Dic[key];
// }
// else
// {
// return Zh_CN_Dic[key];
// }
//}
public static string GetLanguageDictionary(string key) #endregion
{
try
{
var type = Thread.CurrentThread.CurrentUICulture.Name;
if (type == "zh-CN")
{
return Zh_CN_Dic[key];
}
else
{
return En_US_Dic[key];
}
}
catch (Exception)
{
return string.Empty;
}
}
#endregion #endregion