Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
commit
5745161142
|
@ -77,7 +77,7 @@ namespace IRaCIS.Core.Application.Service.BusinessFilter
|
|||
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.DeclaredType = apiResponse.GetType();
|
||||
|
|
|
@ -18,6 +18,8 @@ using Microsoft.AspNetCore.Authorization;
|
|||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.AspNetCore.StaticFiles;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
|
@ -43,6 +45,28 @@ namespace IRaCIS.Core.API.Controllers
|
|||
|
||||
#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]
|
||||
public abstract class UploadBaseController : ControllerBase
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
using System;
|
||||
|
@ -62,14 +63,6 @@ builder.Configuration.AddJsonFile(ConfigMapFileProvider.FromRelativePath(""), "a
|
|||
builder.Host.UseSerilog();
|
||||
|
||||
|
||||
#region Autofac 废弃
|
||||
//builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
|
||||
// .ConfigureContainer<ContainerBuilder>(containerBuilder =>
|
||||
// {
|
||||
// containerBuilder.RegisterModule<AutofacModuleSetup>();
|
||||
// }).UseWindowsService();
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
@ -79,8 +72,8 @@ var _configuration = builder.Configuration;
|
|||
//手动注册服务
|
||||
builder.Services.ConfigureServices(_configuration);
|
||||
|
||||
//异常处理
|
||||
//builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
|
||||
//minimal api 异常处理
|
||||
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
|
||||
//builder.Services.AddProblemDetails();
|
||||
|
||||
//健康检查
|
||||
|
@ -91,7 +84,6 @@ builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resourc
|
|||
// 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim()
|
||||
builder.Services.AddControllers(options =>
|
||||
{
|
||||
//options.Filters.Add<LogActionFilter>();
|
||||
options.Filters.Add<ModelActionFilter>();
|
||||
options.Filters.Add<ProjectExceptionFilter>();
|
||||
options.Filters.Add<UnitOfWorkFilter>();
|
||||
|
@ -148,7 +140,11 @@ builder.Services.AddMasaMinimalAPIs(options =>
|
|||
options.DeletePrefixes = new List<string> { "Delete", "Remove" };
|
||||
|
||||
options.RouteHandlerBuilder= t=> {
|
||||
t.RequireAuthorization().AddEndpointFilter<UnifiedApiResultEndpointFilter>().WithGroupName("Institution");
|
||||
t.RequireAuthorization()
|
||||
.AddEndpointFilter<LimitUserRequestAuthorizationEndpointFilter>()
|
||||
.AddEndpointFilter<ModelValidationEndpointFilter>()
|
||||
.AddEndpointFilter<UnifiedApiResultEndpointFilter>()
|
||||
.WithGroupName("Institution");
|
||||
};
|
||||
options.DisableTrimMethodPrefix = true; //禁用去除方法前缀
|
||||
options.DisableAutoMapRoute = false;//可通过配置true禁用全局自动路由映射或者删除此配置以启用全局自动路由映射
|
||||
|
@ -186,28 +182,8 @@ app.UseStatusCodePages(async context =>
|
|||
|
||||
});
|
||||
|
||||
//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);
|
||||
|
||||
//}
|
||||
// });
|
||||
//});
|
||||
//app.UseExceptionHandler();
|
||||
app.UseExceptionHandler(o => { });
|
||||
|
||||
#region 暂时废弃
|
||||
|
||||
|
@ -272,10 +248,16 @@ app.MapMasaMinimalAPIs();
|
|||
// Serilog
|
||||
SerilogExtension.AddSerilogSetup(enviromentName, app.Services);
|
||||
|
||||
|
||||
//设置国际化I18n
|
||||
var localizer = app.Services.GetRequiredService<IStringLocalizer>();
|
||||
I18n.SetLocalizer(localizer);
|
||||
|
||||
var hangfireJobService = app.Services.GetRequiredService<IIRaCISHangfireJob>();
|
||||
|
||||
await hangfireJobService.InitHangfireJobTaskAsync();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
#region 运行环境 部署平台
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
using Hangfire;
|
||||
using Hangfire.Storage;
|
||||
using IRaCIS.Core.Application.Helper;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using MassTransit;
|
||||
using MassTransit.Scheduling;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service.BackGroundJob
|
||||
|
@ -9,15 +12,13 @@ namespace IRaCIS.Core.Application.Service.BackGroundJob
|
|||
|
||||
public interface IIRaCISHangfireJob
|
||||
{
|
||||
|
||||
//Task MemoryCacheTrialStatusAsync();
|
||||
|
||||
Task InitHangfireJobTaskAsync();
|
||||
|
||||
}
|
||||
public class IRaCISCHangfireJob(ILogger<IRaCISCHangfireJob> _logger,
|
||||
IRepository<Internationalization> _internationalizationRepository,
|
||||
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository
|
||||
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository,
|
||||
IMessageScheduler _IMessageScheduler
|
||||
) : IIRaCISHangfireJob
|
||||
{
|
||||
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();
|
||||
|
||||
#region 废弃
|
||||
////项目状态 立即加载到缓存中
|
||||
//await MemoryCacheTrialStatusAsync();
|
||||
|
||||
////await MemoryCacheAnonymizeData();
|
||||
|
||||
|
||||
////创建项目缓存 定时任务
|
||||
//HangfireJobHelper.AddOrUpdateInitCronJob<IIRaCISHangfireJob>("RecurringJob_Cache_TrialState", t => t.MemoryCacheTrialStatusAsync(), Cron.Daily());
|
||||
#endregion
|
||||
|
||||
|
||||
_logger.LogInformation("项目启动 hangfire 任务初始化 执行结束");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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)
|
||||
.Select(t => new { t.Id, t.Code, t.EmailCron, t.BusinessScenarioEnum, t.TrialId })
|
||||
|
@ -76,24 +63,29 @@ namespace IRaCIS.Core.Application.Service.BackGroundJob
|
|||
//利用主键作为任务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);
|
||||
}
|
||||
|
||||
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);
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
|
@ -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)
|
||||
{
|
|
@ -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
|
||||
{
|
||||
//继续
|
||||
}
|
||||
}
|
||||
}
|
|
@ -83,7 +83,7 @@ public class UnifiedApiResultFilter : Attribute, IAsyncResultFilter
|
|||
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.DeclaredType = apiResponse.GetType();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -11,14 +12,8 @@ namespace IRaCIS.Core.Application.Service.BusinessFilter;
|
|||
#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)
|
||||
{
|
||||
|
@ -37,8 +32,13 @@ public class UnifiedApiResultEndpointFilter : IEndpointFilter
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
{
|
||||
//继续
|
||||
}
|
||||
}
|
||||
}
|
|
@ -135,7 +135,7 @@ public static class FileStoreHelper
|
|||
if (doc == null)
|
||||
{
|
||||
//---数据库没有找到对应的数据模板文件,请联系系统运维人员。
|
||||
throw new BusinessValidationFailedException(StaticData.International("FileStore_TemplateFileNotFound"));
|
||||
throw new BusinessValidationFailedException(I18n.T("FileStore_TemplateFileNotFound"));
|
||||
}
|
||||
|
||||
var filePath = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, doc.Path);
|
||||
|
@ -143,7 +143,7 @@ public static class FileStoreHelper
|
|||
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('/'));
|
||||
|
@ -269,7 +269,7 @@ public static class FileStoreHelper
|
|||
{
|
||||
|
||||
//---解析Json文件配置出现问题
|
||||
throw new BusinessValidationFailedException(StaticData.International("SysMon_JsonConfig") + e.Message);
|
||||
throw new BusinessValidationFailedException(I18n.T("SysMon_JsonConfig") + e.Message);
|
||||
}
|
||||
|
||||
//默认存储的路径
|
||||
|
|
|
@ -64,10 +64,10 @@ namespace IRaCIS.Core.Application.Helper
|
|||
case EmailBusinessScenario.QCTask:
|
||||
HangfireJobHelper.AddOrUpdateCronJob<IEmailSendService>(jobId, t => t.SendTrialImageQCTaskEmailAsync(trialId), emailCron);
|
||||
break;
|
||||
case EmailBusinessScenario.QCQuestion:
|
||||
case EmailBusinessScenario.CRCToQCQuestion:
|
||||
HangfireJobHelper.AddOrUpdateCronJob<IEmailSendService>(jobId, t => t.SendTrialQCQuestionEmailAsync(trialId), emailCron);
|
||||
break;
|
||||
case EmailBusinessScenario.ImageQuestion:
|
||||
case EmailBusinessScenario.QCToCRCImageQuestion:
|
||||
HangfireJobHelper.AddOrUpdateCronJob<IEmailSendService>(jobId, t => t.SendTrialImageQuestionAsync(trialId), emailCron);
|
||||
break;
|
||||
|
||||
|
|
|
@ -4,201 +4,134 @@ using IRaCIS.Core.Infrastructure;
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SharpCompress.Common;
|
||||
|
||||
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 string JsonFileFolder = Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources);
|
||||
|
||||
public static FileSystemWatcher FileSystemWatcher_US { get; set; }
|
||||
public static FileSystemWatcher FileSystemWatcher_CN { get; set; }
|
||||
public static string USJsonPath = Path.Combine(JsonFileFolder, StaticData.En_US_Json);
|
||||
public static string CNJsonPath = Path.Combine(JsonFileFolder, StaticData.Zh_CN_Json);
|
||||
|
||||
private static void VerifyFolder()
|
||||
static InternationalizationHelper()
|
||||
{
|
||||
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);
|
||||
var cnJsonPath = Path.Combine(JsonFileFolder, StaticData.Zh_CN_Json);
|
||||
public static async Task AddOrUpdateJsonKeyValueAsync(IRCGlobalInfoDTO info)
|
||||
{
|
||||
var list = new List<IRCGlobalInfoDTO>() { info };
|
||||
|
||||
await StoreInfoToFileAsync(list);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//更新json 文件 同时更新内存缓存的数据
|
||||
foreach (var filePath in new string[] { usJsonPath, cnJsonPath })
|
||||
public static async Task StoreInfoToFileAsync(List<IRCGlobalInfoDTO> list)
|
||||
{
|
||||
foreach (var filePath in new string[] { USJsonPath, CNJsonPath })
|
||||
{
|
||||
var json = await File.ReadAllTextAsync(filePath);
|
||||
|
||||
JObject jsonObject = JObject.Parse(json, new JsonLoadSettings() { CommentHandling = CommentHandling.Load });
|
||||
|
||||
// 添加或更新指定的键值对
|
||||
|
||||
if (filePath.Contains(StaticData.En_US_Json))
|
||||
{
|
||||
foreach (var item in batchAddDtos)
|
||||
foreach (var tojsonItem in list)
|
||||
{
|
||||
jsonObject[item.Code] = item.Value;
|
||||
|
||||
StaticData.En_US_Dic[item.Code] = item.Value;
|
||||
jsonObject[tojsonItem.Code] = tojsonItem.Value;
|
||||
|
||||
//日志记录该信息方便自己人看, 返回给客户的是配置的
|
||||
StaticData.Log_Locoalize_Dic[item.Code] = item.Description;
|
||||
StaticData.Localizer_Dev_Dic[tojsonItem.Code] = tojsonItem.Description;
|
||||
}
|
||||
}
|
||||
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());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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 文件 同时更新内存缓存的数据
|
||||
foreach (var filePath in new string[] { usJsonPath, cnJsonPath })
|
||||
{
|
||||
var json = await File.ReadAllTextAsync(filePath);
|
||||
#region 监测Json文件变更 实时刷新数据 废弃
|
||||
//FileSystemWatcher_US = new FileSystemWatcher
|
||||
//{
|
||||
// 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 });
|
||||
|
||||
// 添加或更新指定的键值对
|
||||
|
||||
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;
|
||||
}
|
||||
//};
|
||||
//// 添加文件更改事件的处理程序
|
||||
//FileSystemWatcher_US.Changed += (sender, e) => LoadJsonFile(StaticData.Folder.Resources + "\\" + StaticData.En_US_Json);
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
//查询数据库的数据
|
||||
var toJsonList = await _internationalizationRepository.Where(t => t.InternationalizationType == 1).Select(t => new
|
||||
{
|
||||
t.Code,
|
||||
t.Value,
|
||||
t.ValueCN,
|
||||
t.Description
|
||||
}).ToListAsync();
|
||||
//private static void LoadJsonFile(string filePath)
|
||||
//{
|
||||
// Console.WriteLine("刷新json内存数据");
|
||||
// IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile(filePath, false, false);
|
||||
|
||||
//组织成json 文件
|
||||
// IConfigurationRoot enConfiguration = builder.Build();
|
||||
|
||||
var usJsonPath = Path.Combine(JsonFileFolder, StaticData.En_US_Json);
|
||||
var cnJsonPath = Path.Combine(JsonFileFolder, StaticData.Zh_CN_Json);
|
||||
// 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;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//本地静态文件国际化需要
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
//---没有收件人
|
||||
throw new ArgumentException(StaticData.International("SendEmail_NoRecipient"));
|
||||
throw new ArgumentException(I18n.T("SendEmail_NoRecipient"));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
<ItemGroup>
|
||||
<None Remove="IRaCIS.Core.Application.xml" />
|
||||
<None Remove="Resources\en-US.json" />
|
||||
<None Remove="Resources\zh-CN.json" />
|
||||
<None Remove="Resources\zh_ch.json" />
|
||||
<None Remove="Service\Allocation\TaskConsistentRuleService.cs~RF1603d47.TMP" />
|
||||
<None Remove="Service\Reading\ReadingImageTask\ReadingImageTaskService.cs~RF2f9323.TMP" />
|
||||
|
@ -40,6 +41,9 @@
|
|||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\zh-CN.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -12747,7 +12747,14 @@
|
|||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.BusinessFilter.GlobalExceptionHandler">
|
||||
<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>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Filter.TrialResourceFilter">
|
||||
|
@ -12890,42 +12897,6 @@
|
|||
构造函数注入
|
||||
</summary>
|
||||
</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">
|
||||
<summary>
|
||||
加急的医学反馈任务 通知MIM
|
||||
|
@ -13014,11 +12985,42 @@
|
|||
通知PM 进行一致性核查
|
||||
</summary>
|
||||
</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">
|
||||
<summary>
|
||||
参考链接:https://github.com/MassTransit/MassTransit/discussions/2498
|
||||
</summary>
|
||||
</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">
|
||||
<summary> TaskAllocationRuleView 列表视图模型 </summary>
|
||||
</member>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,6 +54,7 @@ public class TestMasstransitService : BaseService
|
|||
{
|
||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||
|
||||
|
||||
Console.WriteLine(_testLengthRepository._dbContext.GetHashCode());
|
||||
|
||||
//IScopedMediator 上下文一致, IMediator上下文不一致
|
|
@ -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
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -175,7 +175,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
if (addOrEditInternationalization.InternationalizationType == 1)
|
||||
{
|
||||
await InternationalizationHelper.AddOrUpdateJsonKeyValueAsync(entity.Code, addOrEditInternationalization.Value, addOrEditInternationalization.ValueCN, addOrEditInternationalization.Description);
|
||||
await InternationalizationHelper.AddOrUpdateJsonKeyValueAsync(_mapper.Map<IRCGlobalInfoDTO>(addOrEditInternationalization));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using AutoMapper;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Helper;
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service
|
||||
|
@ -70,7 +71,10 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
CreateMap<Internationalization, BatchInternationalizationDto>().ReverseMap();
|
||||
|
||||
CreateMap<Internationalization, IRCGlobalInfoDTO>();
|
||||
|
||||
CreateMap<EventStoreRecord, EventStoreRecordView>();
|
||||
|
||||
CreateMap<BatchAddInternationalizationDto, InternationalizationAddOrEdit>();
|
||||
|
||||
|
||||
|
|
|
@ -203,7 +203,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
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);
|
||||
};
|
||||
|
||||
await SendTrialEmailAsync(trialId, EmailBusinessScenario.ImageQuestion, topicAndHtmlFunc);
|
||||
await SendTrialEmailAsync(trialId, EmailBusinessScenario.QCToCRCImageQuestion, topicAndHtmlFunc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
//---当前已有人正在上传和归档该检查!
|
||||
return ResponseOutput.NotOk(StaticData.International("UploadDownLoad_ArchiveInProgress"));
|
||||
return ResponseOutput.NotOk(I18n.T("UploadDownLoad_ArchiveInProgress"));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -102,7 +102,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
if (cacheValue != Guid.Empty && cacheValue != _userInfo.Id)
|
||||
{
|
||||
//---当前已有人正在上传和归档该检查!
|
||||
return ResponseOutput.NotOk(StaticData.International("UploadDownLoad_ArchiveInProgress"));
|
||||
return ResponseOutput.NotOk(I18n.T("UploadDownLoad_ArchiveInProgress"));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -134,7 +134,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
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
|
||||
{
|
||||
|
|
|
@ -28,7 +28,7 @@ using NPOI.XWPF.UserModel;
|
|||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Tea;
|
||||
|
||||
|
||||
|
||||
namespace IRaCIS.Core.Application.Service
|
||||
|
@ -56,10 +56,25 @@ namespace IRaCIS.Core.Application.Service
|
|||
return Task.FromResult(list);
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
public IResponseOutput GetTest()
|
||||
{
|
||||
|
||||
//throw new BusinessValidationFailedException("手动抛出的异常");
|
||||
|
||||
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()
|
||||
{
|
||||
throw new BusinessValidationFailedException("传统控制器异常");
|
||||
|
||||
var model1 = new TestModel() { TestId = NewId.NextSequentialGuid(), TestName = null };
|
||||
var model2 = new TestModel2() { TestId = NewId.NextSequentialGuid(), TestName = "test2" };
|
||||
|
||||
|
|
|
@ -46,11 +46,13 @@ namespace IRaCIS.Core.Domain.Share
|
|||
|
||||
//Reviewer=4,
|
||||
|
||||
//QC影像质控任务
|
||||
QCTask = 5,
|
||||
|
||||
QCQuestion = 6,
|
||||
|
||||
ImageQuestion = 7,
|
||||
CRCToQCQuestion = 6,
|
||||
|
||||
QCToCRCImageQuestion = 7,
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -4,3 +4,4 @@ global using System;
|
|||
global using System.Collections.Generic;
|
||||
global using System.ComponentModel.DataAnnotations;
|
||||
global using System.ComponentModel.DataAnnotations.Schema;
|
||||
global using IRaCIS.Core.Infrastructure.Extention;
|
||||
|
|
|
@ -62,7 +62,7 @@ public class ReadingQuestionCriterionTrial : BaseAddAuditEntity
|
|||
[Comment("全局阅片评估更新类型")]
|
||||
public string GlobalUpdateType { get; set; } = string.Empty;
|
||||
[Comment("评估原因")]
|
||||
public string EvaluationReason { get; set; } = StaticData.International("CriterionTrial_EvaluationReason");
|
||||
public string EvaluationReason { get; set; } = I18n.T("CriterionTrial_EvaluationReason");
|
||||
[Comment("是否显示详情")]
|
||||
public bool IsShowDetail { get; set; } = true;
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ public partial class Trial : BaseFullDeleteAuditEntity
|
|||
public bool VisitPlanConfirmed { get; set; }
|
||||
|
||||
[Comment("受试者编号具体规则")]
|
||||
public string SubjectCodeRule { get; set; } = StaticData.International("Trial_number");
|
||||
public string SubjectCodeRule { get; set; } = I18n.T("Trial_number");
|
||||
[Comment("是否 提醒受试者编号规则")]
|
||||
public bool IsNoticeSubjectCodeRule { get; set; } = true;
|
||||
|
||||
|
|
|
@ -71,23 +71,9 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
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>
|
||||
/// 设置是使用哪个仓储 默认不跟踪
|
||||
|
@ -171,7 +157,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
if (dbEntity == null)
|
||||
{
|
||||
|
||||
throw new BusinessValidationFailedException(_localizer["Repository_UpdateError"]);
|
||||
throw new BusinessValidationFailedException(I18n.T("Repository_UpdateError"));
|
||||
}
|
||||
|
||||
var dbBeforEntity = dbEntity.Clone();
|
||||
|
@ -450,7 +436,6 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
if (dbEntity == null)
|
||||
{
|
||||
|
||||
throw new BusinessValidationFailedException(_localizer["Repository_UpdateError"]);
|
||||
throw new BusinessValidationFailedException(I18n.T("Repository_UpdateError"));
|
||||
}
|
||||
|
||||
var dbBeforEntity = dbEntity.Clone();
|
||||
|
@ -156,7 +156,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
|
||||
if (searchEntity == null)
|
||||
{
|
||||
throw new BusinessValidationFailedException(_localizer["Repository_UpdateError"]);
|
||||
throw new BusinessValidationFailedException(I18n.T("Repository_UpdateError"));
|
||||
}
|
||||
|
||||
_dbContext.EntityModifyPartialFiled(searchEntity, updateFactory);
|
||||
|
@ -208,7 +208,7 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
|
||||
if (waitDelete == null)
|
||||
{
|
||||
throw new BusinessValidationFailedException(_localizer["Repository_DeleteError"]);
|
||||
throw new BusinessValidationFailedException(I18n.T("Repository_DeleteError"));
|
||||
}
|
||||
|
||||
await DeleteAsync(waitDelete, autoSave);
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
}
|
|
@ -117,9 +117,9 @@ namespace IRaCIS.Core.Infrastructure.Extention
|
|||
|
||||
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);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
|
@ -7,12 +8,7 @@ namespace IRaCIS.Core.Domain.Share;
|
|||
|
||||
public static class StaticData
|
||||
{
|
||||
|
||||
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>();
|
||||
public static Dictionary<string, string> Localizer_Dev_Dic = new Dictionary<string, string>();
|
||||
|
||||
|
||||
#region 国际化
|
||||
|
@ -28,48 +24,34 @@ public static class StaticData
|
|||
public static readonly string en_US_bookMark = "en_us";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取国际化
|
||||
/// </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)
|
||||
{
|
||||
#region 国际化废弃
|
||||
|
||||
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)
|
||||
{
|
||||
try
|
||||
{
|
||||
var type = Thread.CurrentThread.CurrentUICulture.Name;
|
||||
if (type == "zh-CN")
|
||||
{
|
||||
return Zh_CN_Dic[key];
|
||||
#endregion
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return En_US_Dic[key];
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
Loading…
Reference in New Issue