diff --git a/IRC.Core.SCP/HostConfig/EFSetup.cs b/IRC.Core.SCP/HostConfig/EFSetup.cs index 00ee49222..73b279ffc 100644 --- a/IRC.Core.SCP/HostConfig/EFSetup.cs +++ b/IRC.Core.SCP/HostConfig/EFSetup.cs @@ -4,6 +4,7 @@ using IRaCIS.Core.Infra.EFCore; using Medallion.Threading; using Medallion.Threading.SqlServer; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -15,11 +16,12 @@ namespace IRaCIS.Core.SCP { services.AddHttpContextAccessor(); services.AddScoped(); + services.AddScoped(); + - //这个注入没有成功--注入是没问题的,构造函数也只是支持参数就好,错在注入的地方不能写DbContext //Web程序中通过重用池中DbContext实例可提高高并发场景下的吞吐量, 这在概念上类似于ADO.NET Provider原生的连接池操作方式,具有节省DbContext实例化成本的优点 - services.AddDbContextPool(options => + services.AddDbContextPool((sp, options) => { // 在控制台 //public static readonly ILoggerFactory MyLoggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); }); @@ -35,6 +37,7 @@ namespace IRaCIS.Core.SCP options.EnableSensitiveDataLogging(); options.AddInterceptors(new QueryWithNoLockDbCommandInterceptor()); + options.AddInterceptors(sp.GetServices()); options.UseProjectables(); diff --git a/IRaCIS.Core.API/Progranm.cs b/IRaCIS.Core.API/Progranm.cs index 915ff6018..64f3f79a7 100644 --- a/IRaCIS.Core.API/Progranm.cs +++ b/IRaCIS.Core.API/Progranm.cs @@ -29,6 +29,10 @@ using IRaCIS.Core.Application.Service.ImageAndDoc; using IP2Region.Net.Abstractions; using IP2Region.Net.XDB; using IRaCIS.Core.Application.BusinessFilter; +using Microsoft.AspNetCore.Http; +using IRaCIS.Core.Infrastructure.Extention; +using Newtonsoft.Json; +using Microsoft.AspNetCore.Diagnostics; #region 获取环境变量 @@ -164,6 +168,8 @@ builder.Services.AddSingleton(); builder.Services.AddSingleton(new Searcher(CachePolicy.Content, Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources, "ip2region.xdb"))); +//builder.Services.AddExceptionHandler(); +//builder.Services.AddProblemDetails(); #region 历史废弃配置 //builder.Services.AddMemoryCache(); @@ -190,6 +196,56 @@ var env = app.Environment; // Configure the HTTP request pipeline. +#region 异常处理 全局业务异常已统一处理了,非业务错误会来到这里 400 -500状态码 + + +//app.UseStatusCodePagesWithReExecute("/Error/{0}"); + +app.UseStatusCodePages(async context => +{ + var code = context.HttpContext.Response.StatusCode; + context.HttpContext.Response.ContentType = "application/json"; + if (code < 500) + { + await context.HttpContext.Response.WriteAsync(JsonConvert.SerializeObject(ResponseOutput.NotOk($"Client error, actual request error status code({code})"))); + } + else + { + //ResultFilter 里面的异常并不会到这里 + await context.HttpContext.Response.WriteAsync(JsonConvert.SerializeObject((ResponseOutput.NotOk($"Server error , actual request error status code({code})")))); + } + +}); + +//app.UseExceptionHandler(o => { }); + +//这里没生效,原因未知,官方文档也是这种写法,也用了GlobalExceptionHandler 尝试,还是不行,怀疑框架bug +//app.UseExceptionHandler(configure => +//{ +// configure.Run(async context => +// { +// var exceptionHandlerPathFeature = context.Features.Get(); +//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); + + +//} + +// }); +//}); + + + +#endregion + //本地化 app.UseLocalization(); @@ -198,12 +254,11 @@ app.UseForwardedHeaders(); //响应压缩 app.UseResponseCompression(); -//app.UseCors(t => t.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()); //不需要 token 访问的静态文件 wwwroot css, JavaScript, and images don't require authentication. app.UseStaticFiles(); -app.UseMiddleware(); + //LogDashboard app.UseLogDashboard("/LogDashboard"); @@ -211,22 +266,24 @@ app.UseLogDashboard("/LogDashboard"); //hangfire app.UseHangfireConfig(env); +#region 暂时废弃 +//app.UseMiddleware(); ////限流 中间件 //app.UseIpRateLimiting(); +//if (env.IsDevelopment()) +//{ +// app.UseDeveloperExceptionPage(); +//} +//else +//{ +// //app.UseHsts(); +//} +#endregion + -if (env.IsDevelopment()) -{ - app.UseDeveloperExceptionPage(); -} -else -{ - //app.UseHsts(); -} -// 特殊异常处理 比如 404 -app.UseStatusCodePagesWithReExecute("/Error/{0}"); SwaggerSetup.Configure(app, env); diff --git a/IRaCIS.Core.API/_ServiceExtensions/EFSetup.cs b/IRaCIS.Core.API/_ServiceExtensions/EFSetup.cs index 820a2a67e..ae82e3027 100644 --- a/IRaCIS.Core.API/_ServiceExtensions/EFSetup.cs +++ b/IRaCIS.Core.API/_ServiceExtensions/EFSetup.cs @@ -7,6 +7,7 @@ using IRaCIS.Core.Infra.EFCore; using Medallion.Threading; using Medallion.Threading.SqlServer; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -21,12 +22,14 @@ namespace IRaCIS.Core.API services.AddHttpContextAccessor(); services.AddScoped(); + services.AddScoped(); + // First, register a pooling context factory as a Singleton service, as usual: //这个注入没有成功--注入是没问题的,构造函数也只是支持参数就好,错在注入的地方不能写DbContext //Web程序中通过重用池中DbContext实例可提高高并发场景下的吞吐量, 这在概念上类似于ADO.NET Provider原生的连接池操作方式,具有节省DbContext实例化成本的优点 - services.AddDbContext(options => + services.AddDbContext((sp, options) => { // 在控制台 @@ -43,6 +46,7 @@ namespace IRaCIS.Core.API options.EnableSensitiveDataLogging(); options.AddInterceptors(new QueryWithNoLockDbCommandInterceptor()); + options.AddInterceptors(sp.GetServices()); options.UseProjectables(); diff --git a/IRaCIS.Core.API/appsettings.Uat_IRC.json b/IRaCIS.Core.API/appsettings.Uat_IRC.json index a107b1342..8176d5f8a 100644 --- a/IRaCIS.Core.API/appsettings.Uat_IRC.json +++ b/IRaCIS.Core.API/appsettings.Uat_IRC.json @@ -75,7 +75,11 @@ "CompanyNameCN": "上海展影医疗科技有限公司", "CompanyShortName": "Extensive Imaging", "CompanyShortNameCN": "展影医疗" + }, + + "SystemPacsConfig": { + "Port": "11113", + "IP": "47.117.164.182" } - } diff --git a/IRaCIS.Core.Application/BusinessFilter/GlobalExceptionHandler.cs b/IRaCIS.Core.Application/BusinessFilter/GlobalExceptionHandler.cs new file mode 100644 index 000000000..bdd19c962 --- /dev/null +++ b/IRaCIS.Core.Application/BusinessFilter/GlobalExceptionHandler.cs @@ -0,0 +1,50 @@ +using Microsoft.AspNetCore.Diagnostics; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + +namespace IRaCIS.Core.Application.BusinessFilter +{ + + /// + /// 不生效,不知道为啥 + /// + public class GlobalExceptionHandler : IExceptionHandler + { + private readonly ILogger _logger; + public GlobalExceptionHandler(ILogger logger) + { + this._logger = logger; + } + public ValueTask 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); + } + } +} diff --git a/IRaCIS.Core.Application/BusinessFilter/ProjectExceptionFilter.cs b/IRaCIS.Core.Application/BusinessFilter/ProjectExceptionFilter.cs index 823c168da..011e9ceae 100644 --- a/IRaCIS.Core.Application/BusinessFilter/ProjectExceptionFilter.cs +++ b/IRaCIS.Core.Application/BusinessFilter/ProjectExceptionFilter.cs @@ -45,6 +45,7 @@ namespace IRaCIS.Core.Application.Filter context.Result = new JsonResult(ResponseOutput.NotOk(context.Exception.Message, "", error!.Code, localizedInfo: info)); + //warning 级别记录 //_logger.LogWarning($"[{error!.LocalizedKey}]:{StaticData.Log_Locoalize_Dic[error!.LocalizedKey]}"); } @@ -60,12 +61,17 @@ namespace IRaCIS.Core.Application.Filter _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 { //继续 } - context.ExceptionHandled = true;//标记当前异常已经被处理过了 } } } diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml index 36374a2b0..3aa7acb09 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml @@ -29,31 +29,16 @@ 签名 + + + 不生效,不知道为啥 + + 主要为了 处理项目结束 锁库,不允许操作 - - - - - - - - - - - - - - - - - - - - 写文件导到磁盘 @@ -62,28 +47,6 @@ 文件保存路径 - - - 上传截图 - - - - - - - - - - - 通用获取文件路径 - - - - - - - - oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder diff --git a/IRaCIS.Core.Application/Service/Common/CommonDocumentService.cs b/IRaCIS.Core.Application/Service/Common/CommonDocumentService.cs index 59038b64f..35eac6a73 100644 --- a/IRaCIS.Core.Application/Service/Common/CommonDocumentService.cs +++ b/IRaCIS.Core.Application/Service/Common/CommonDocumentService.cs @@ -41,7 +41,7 @@ namespace IRaCIS.Core.Application.Service .WhereIf(string.IsNullOrEmpty(queryCommonDocument.Name), t => t.Name.Contains(queryCommonDocument.Name)) .ProjectTo(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken, userId = _userInfo.Id }); - return await commonDocumentQueryable.ToPagedListAsync(queryCommonDocument.PageIndex, queryCommonDocument.PageSize, String.IsNullOrEmpty(queryCommonDocument.SortField) ? nameof(CommonDocument.Code) : queryCommonDocument.SortField, queryCommonDocument.Asc); ; + return await commonDocumentQueryable.ToPagedListAsync(queryCommonDocument); } diff --git a/IRaCIS.Core.Application/Service/Document/Interface/ITrialDocumentService.cs b/IRaCIS.Core.Application/Service/Document/Interface/ITrialDocumentService.cs index f9957b755..9060e8f1a 100644 --- a/IRaCIS.Core.Application/Service/Document/Interface/ITrialDocumentService.cs +++ b/IRaCIS.Core.Application/Service/Document/Interface/ITrialDocumentService.cs @@ -25,7 +25,7 @@ namespace IRaCIS.Core.Application.Contracts Task> GetTrialUserSelect(Guid trialId); - PageOutput GetTrialSystemDocumentList(DocumentTrialUnionQuery querySystemDocument); + Task> GetTrialSystemDocumentList(DocumentTrialUnionQuery querySystemDocument); List GetTrialUserDocumentList(Guid trialId); } } \ No newline at end of file diff --git a/IRaCIS.Core.Application/Service/Document/TrialDocumentService.cs b/IRaCIS.Core.Application/Service/Document/TrialDocumentService.cs index 1c32b6040..44f1b0324 100644 --- a/IRaCIS.Core.Application/Service/Document/TrialDocumentService.cs +++ b/IRaCIS.Core.Application/Service/Document/TrialDocumentService.cs @@ -26,8 +26,8 @@ namespace IRaCIS.Core.Application.Services private readonly IRepository _trialDocumentRepository; private readonly IRepository _trialDocUserTypeConfirmedUserRepository; private readonly IRepository _trialRepository; - private readonly ISystemDocumentService _systemDocumentService; - private readonly IRepository _systemDocConfirmedUserRepository; + private readonly ISystemDocumentService _systemDocumentService; + private readonly IRepository _systemDocConfirmedUserRepository; private readonly IRepository _systemDocumentRepository; private readonly IRepository _trialCriterionAdditionalAssessmentTypeRepository; private readonly IRepository _readingQuestionCriterionTrialRepository; @@ -36,8 +36,8 @@ namespace IRaCIS.Core.Application.Services public TrialDocumentService(IRepository trialDocumentRepository, IRepository trialDocUserTypeConfirmedUserRepository, IRepository trialRepository, - ISystemDocumentService systemDocumentService, - IRepository systemDocConfirmedUserRepository, + ISystemDocumentService systemDocumentService, + IRepository systemDocConfirmedUserRepository, IRepository trialCriterionAdditionalAssessmentTypeRepository, IRepository readingQuestionCriterionTrialRepository , IRepository systemDocumentRepository) @@ -45,8 +45,8 @@ namespace IRaCIS.Core.Application.Services _trialDocumentRepository = trialDocumentRepository; this._trialDocUserTypeConfirmedUserRepository = trialDocUserTypeConfirmedUserRepository; this._trialRepository = trialRepository; - this._systemDocumentService = systemDocumentService; - this._systemDocConfirmedUserRepository = systemDocConfirmedUserRepository; + this._systemDocumentService = systemDocumentService; + this._systemDocConfirmedUserRepository = systemDocConfirmedUserRepository; _systemDocumentRepository = systemDocumentRepository; _readingQuestionCriterionTrialRepository = readingQuestionCriterionTrialRepository; _trialCriterionAdditionalAssessmentTypeRepository = trialCriterionAdditionalAssessmentTypeRepository; @@ -64,7 +64,7 @@ namespace IRaCIS.Core.Application.Services var trialDocumentQueryable = _trialDocumentRepository.AsQueryable(true).Where(t => t.TrialId == queryTrialDocument.TrialId) .WhereIf(!string.IsNullOrEmpty(queryTrialDocument.Name), t => t.Name.Contains(queryTrialDocument.Name)) .WhereIf(queryTrialDocument.FileTypeId != null, t => t.FileTypeId == queryTrialDocument.FileTypeId) - .WhereIf(queryTrialDocument.UserTypeId != null, t => t.NeedConfirmedUserTypeList.Any(t=>t.NeedConfirmUserTypeId== queryTrialDocument.UserTypeId) ) + .WhereIf(queryTrialDocument.UserTypeId != null, t => t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == queryTrialDocument.UserTypeId)) .WhereIf(queryTrialDocument.IsDeleted != null, t => t.IsDeleted == queryTrialDocument.IsDeleted) .ProjectTo(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken, isEn_Us = _userInfo.IsEn_Us }); @@ -75,17 +75,17 @@ namespace IRaCIS.Core.Application.Services public async Task> GetTrialSignDocumentList(TrialDocQuery querySystemDocument) { var trialDocQueryable = from trialDoc in _trialDocumentRepository.AsQueryable(true) - .WhereIf(querySystemDocument.TrialId!=null,t=>t.TrialId==querySystemDocument.TrialId) - .Where(t => t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == _userInfo.UserTypeId) ) + .WhereIf(querySystemDocument.TrialId != null, t => t.TrialId == querySystemDocument.TrialId) + .Where(t => t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == _userInfo.UserTypeId)) - join trialUser in _repository.Where(t=>t.UserId==_userInfo.Id) on trialDoc.TrialId equals trialUser.TrialId + join trialUser in _repository.Where(t => t.UserId == _userInfo.Id) on trialDoc.TrialId equals trialUser.TrialId join confirm in _repository.Where() on new { trialUser.UserId, TrialDocumentId = trialDoc.Id } equals new { UserId = confirm.ConfirmUserId, confirm.TrialDocumentId } into cc from confirm in cc.DefaultIfEmpty() select new TrialSignDocView() { - TrialCode=trialDoc.Trial.TrialCode, + TrialCode = trialDoc.Trial.TrialCode, ResearchProgramNo = trialDoc.Trial.ResearchProgramNo, ExperimentName = trialDoc.Trial.ExperimentName, Id = trialDoc.Id, @@ -116,7 +116,7 @@ namespace IRaCIS.Core.Application.Services .WhereIf(querySystemDocument.IsSigned == false, t => t.ConfirmTime == null); - return await trialDocQueryable.ToPagedListAsync(querySystemDocument.PageIndex, querySystemDocument.PageSize, querySystemDocument.SortField, querySystemDocument.Asc); + return await trialDocQueryable.ToPagedListAsync(querySystemDocument.PageIndex, querySystemDocument.PageSize, querySystemDocument.SortField, querySystemDocument.Asc); } @@ -142,19 +142,19 @@ namespace IRaCIS.Core.Application.Services PageSize = 1, })).Data; } - else + else { result = await _systemDocumentService.getWaitSignSysDocList(new SystemDocumentQuery() { - PageIndex=1, + PageIndex = 1, IsSigned = false, - PageSize=1, - Asc=false, - SortField="UpdateTime", - }); + PageSize = 1, + Asc = false, + SortField = "UpdateTime", + }); + + } - } - if (result.CurrentPageData.Count > 0) { @@ -823,7 +823,7 @@ namespace IRaCIS.Core.Application.Services /// [HttpPost] [Obsolete] - public PageOutput GetTrialSystemDocumentList(DocumentTrialUnionQuery querySystemDocument) + public async Task> GetTrialSystemDocumentList(DocumentTrialUnionQuery querySystemDocument) { var systemDocumentQueryable = _repository .WhereIf(!_userInfo.IsAdmin, t => t.IsDeleted == false) @@ -867,7 +867,7 @@ namespace IRaCIS.Core.Application.Services .WhereIf(!string.IsNullOrEmpty(querySystemDocument.Name), t => t.Name.Contains(querySystemDocument.Name)) .WhereIf(querySystemDocument.FileTypeId != null, t => t.FileTypeId == querySystemDocument.FileTypeId); - return unionQuery.ToPagedList(querySystemDocument.PageIndex, querySystemDocument.PageSize, querySystemDocument.SortField, querySystemDocument.Asc); + return await unionQuery.ToPagedListAsync(querySystemDocument.PageIndex, querySystemDocument.PageSize, querySystemDocument.SortField, querySystemDocument.Asc); } #endregion diff --git a/IRaCIS.Core.Application/Service/QC/QCQuestionService.cs b/IRaCIS.Core.Application/Service/QC/QCQuestionService.cs index 1d574c465..3e9a526e9 100644 --- a/IRaCIS.Core.Application/Service/QC/QCQuestionService.cs +++ b/IRaCIS.Core.Application/Service/QC/QCQuestionService.cs @@ -103,8 +103,10 @@ namespace IRaCIS.Core.Application.Contracts .OrderByDescending(x=>x.LanguageType) .ThenBy(t=>t.ShowOrder) .ProjectTo(_mapper.ConfigurationProvider); - - return await QCQuestionQueryable.ToPagedListAsync(queryQCQuestionConfigure.PageIndex, queryQCQuestionConfigure.PageSize, new string[2] { "LanguageType desc", "ShowOrder asc" }); + + var defalutSortArray = new string[] { nameof(QCQuestionConfigureView.LanguageType) + " desc", nameof(QCQuestionConfigureView.ShowOrder) }; + + return await QCQuestionQueryable.ToPagedListAsync(queryQCQuestionConfigure.PageIndex, queryQCQuestionConfigure.PageSize, new string[2] { "LanguageType desc", "ShowOrder asc" }); } public async Task AddOrUpdateQCQuestionConfigure(QCQuestionAddOrEdit addOrEditQCQuestionConfigure) diff --git a/IRaCIS.Core.Application/Service/Reading/ClinicalData/ClinicalAnswerService.cs b/IRaCIS.Core.Application/Service/Reading/ClinicalData/ClinicalAnswerService.cs index 19ca221bf..8f299b175 100644 --- a/IRaCIS.Core.Application/Service/Reading/ClinicalData/ClinicalAnswerService.cs +++ b/IRaCIS.Core.Application/Service/Reading/ClinicalData/ClinicalAnswerService.cs @@ -637,8 +637,9 @@ namespace IRaCIS.Core.Application.Service ModuleName=x.ModuleName, }); + var defalutSortArray = new string[] { nameof(GetCRCConfirmListOutDto.SubjectCode) + " desc", nameof(GetCRCConfirmListOutDto.LatestScanDate) }; - var result = await query.ToPagedListAsync(inDto.PageIndex, inDto.PageSize, new string[2] { "SubjectCode asc", "LatestScanDate asc" }); + var result = await query.ToPagedListAsync(inDto.PageIndex, inDto.PageSize, new string[2] { "SubjectCode asc", "LatestScanDate asc" }); var formList = await _clinicalFormRepository.Where(x => x.TrialId == inDto.TrialId) .Where(x => x.ClinicalDataTrialSet.UploadRole == UploadRole.CRC) diff --git a/IRaCIS.Core.Application/Service/Reading/MedicalAudit/ReadingMedicineQuestionService.cs b/IRaCIS.Core.Application/Service/Reading/MedicalAudit/ReadingMedicineQuestionService.cs index 12ab48a55..a148bed8f 100644 --- a/IRaCIS.Core.Application/Service/Reading/MedicalAudit/ReadingMedicineQuestionService.cs +++ b/IRaCIS.Core.Application/Service/Reading/MedicalAudit/ReadingMedicineQuestionService.cs @@ -65,7 +65,9 @@ namespace IRaCIS.Core.Application.Service .WhereIf(inDto.LanguageType != null, x => x.LanguageType == inDto.LanguageType!.Value) .ProjectTo(_mapper.ConfigurationProvider).OrderBy(x => x.ShowOrder); - return await query.ToPagedListAsync(inDto.PageIndex, inDto.PageSize, new string[2] { "LanguageType desc", "ShowOrder asc" }); + var defalutSortArray = new string[] { nameof(ReadingMedicineSystemQuestionView.LanguageType) + " desc", nameof(ReadingMedicineSystemQuestionView.ShowOrder) }; + + return await query.ToPagedListAsync(inDto.PageIndex, inDto.PageSize, new string[2] { "LanguageType desc", "ShowOrder asc" }); } /// diff --git a/IRaCIS.Core.Application/Service/TrialSiteUser/TrialSiteDicomAEService.cs b/IRaCIS.Core.Application/Service/TrialSiteUser/TrialSiteDicomAEService.cs index 7bd160513..5ed3452e0 100644 --- a/IRaCIS.Core.Application/Service/TrialSiteUser/TrialSiteDicomAEService.cs +++ b/IRaCIS.Core.Application/Service/TrialSiteUser/TrialSiteDicomAEService.cs @@ -51,8 +51,7 @@ namespace IRaCIS.Core.Application.Service { var verifyExp1 = new EntityVerifyExp() { - VerifyExp = u => u.IP == addOrEditTrialSiteDicomAE.IP && u.Port == addOrEditTrialSiteDicomAE.Port - && u.CallingAE == addOrEditTrialSiteDicomAE.CallingAE && u.TrialId == addOrEditTrialSiteDicomAE.TrialId + VerifyExp = u => u.CallingAE == addOrEditTrialSiteDicomAE.CallingAE && u.TrialId == addOrEditTrialSiteDicomAE.TrialId && u.TrialSiteId == addOrEditTrialSiteDicomAE.TrialSiteId, //"不允许添加相同的记录" diff --git a/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs b/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs index 9985806ed..15414fe37 100644 --- a/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs +++ b/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs @@ -511,7 +511,6 @@ namespace IRaCIS.Core.Infra.EFCore public override async Task SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken()) { // 采用触发器的方式 设置 CreateUserId CreateTime UpdateTime UpdateUserId 稽查实体里面没有这四个字段的值 因为先后顺序的原因 - SetCommonEntityAuditInfo(); await AddAudit(); try @@ -595,85 +594,7 @@ namespace IRaCIS.Core.Infra.EFCore } - /// - /// 重写savechange方式 统一增加审计信息 CreateUserId CreateTime UpdateTime Update UserId - /// - private void SetCommonEntityAuditInfo() - { - ChangeTracker.DetectChanges(); // Important! - - // 获取所有更改,删除,新增的实体,但排除审计实体(避免死循环) - var entities = ChangeTracker.Entries() - .Where(u => (u.State == EntityState.Modified || u.State == EntityState.Deleted || u.State == EntityState.Added)).Where(x => !typeof(DataInspection).IsAssignableFrom(x.Entity.GetType())).ToList(); - - foreach (var t in entities) - { - switch (t.State) - { - - case EntityState.Deleted: - - break; - case EntityState.Modified: - - if (t.Entity is IAuditUpdate updateEntity1) - { - updateEntity1.UpdateTime = DateTime.Now; - updateEntity1.UpdateUserId = _userInfo.Id; - } - - if (t.Entity is ISoftDelete softDelete) - { - if (softDelete.IsDeleted) - { - softDelete.DeleteUserId = _userInfo.Id; - softDelete.DeletedTime = DateTime.Now; - } - else - { - softDelete.DeletedTime = null; - } - } - - break; - //添加的时候,更新审计字段也赋值 - case EntityState.Added: - - - if (t.Entity is IAuditAdd addEntity) - { - if (addEntity.CreateTime == default(DateTime)) - { - addEntity.CreateTime = DateTime.Now; - } - - addEntity.CreateUserId = _userInfo.Id; - } - - if (t.Entity is IAuditUpdate updateEntity) - { - updateEntity.UpdateTime = DateTime.Now; - updateEntity.UpdateUserId = _userInfo.Id; - } - - if (t.Entity is IAuditAddWithUserName addEntity3) - { - if (addEntity3.CreateTime == default(DateTime)) - { - addEntity3.CreateTime = DateTime.Now; - - } - - addEntity3.CreateUserId = _userInfo.Id; - addEntity3.CreateUser = _userInfo.RealName; - } - break; - } - } - - - } public virtual DbSet TaskAllocationRule { get; set; } diff --git a/IRaCIS.Core.Infra.EFCore/Interceptor/AuditEntityInterceptor.cs b/IRaCIS.Core.Infra.EFCore/Interceptor/AuditEntityInterceptor.cs new file mode 100644 index 000000000..b2f99decd --- /dev/null +++ b/IRaCIS.Core.Infra.EFCore/Interceptor/AuditEntityInterceptor.cs @@ -0,0 +1,103 @@ +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + + +namespace IRaCIS.Core.Infra.EFCore; + +public class AuditEntityInterceptor(IUserInfo _userInfo) : SaveChangesInterceptor +{ + public override InterceptionResult SavingChanges(DbContextEventData eventData, InterceptionResult result) + { + AuditEntities(eventData.Context); + + return base.SavingChanges(eventData, result); + } + + public override ValueTask> SavingChangesAsync(DbContextEventData eventData, + InterceptionResult result, CancellationToken cancellationToken = default) + { + AuditEntities(eventData.Context); + + return base.SavingChangesAsync(eventData, result, cancellationToken); + } + + public void AuditEntities(DbContext? context) + { + if (context == null) return; + + // 获取所有更改,删除,新增的实体,但排除审计实体(避免死循环) + foreach (var entry in context.ChangeTracker.Entries().Where(u => (u.State == EntityState.Modified || u.State == EntityState.Added)) + .Where(x => !typeof(DataInspection).IsAssignableFrom(x.Entity.GetType())).ToList()) + { + switch (entry.State) + { + + case EntityState.Deleted: + + break; + case EntityState.Modified: + + if (entry.Entity is IAuditUpdate updateEntity1) + { + updateEntity1.UpdateTime = DateTime.Now; + updateEntity1.UpdateUserId = _userInfo.Id; + } + + if (entry.Entity is ISoftDelete softDelete) + { + if (softDelete.IsDeleted) + { + softDelete.DeleteUserId = _userInfo.Id; + softDelete.DeletedTime = DateTime.Now; + } + else + { + softDelete.DeletedTime = null; + } + } + + break; + //添加的时候,更新审计字段也赋值 + case EntityState.Added: + + + if (entry.Entity is IAuditAdd addEntity) + { + if (addEntity.CreateTime == default(DateTime)) + { + addEntity.CreateTime = DateTime.Now; + } + + addEntity.CreateUserId = _userInfo.Id; + } + + if (entry.Entity is IAuditUpdate updateEntity) + { + updateEntity.UpdateTime = DateTime.Now; + updateEntity.UpdateUserId = _userInfo.Id; + } + + if (entry.Entity is IAuditAddWithUserName addEntity3) + { + if (addEntity3.CreateTime == default(DateTime)) + { + addEntity3.CreateTime = DateTime.Now; + + } + + addEntity3.CreateUserId = _userInfo.Id; + addEntity3.CreateUser = _userInfo.RealName; + } + break; + } + } + + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EFCore/Interceptor/AuditInterceptor.cs b/IRaCIS.Core.Infra.EFCore/Interceptor/OldAuditInterceptor.cs similarity index 100% rename from IRaCIS.Core.Infra.EFCore/Interceptor/AuditInterceptor.cs rename to IRaCIS.Core.Infra.EFCore/Interceptor/OldAuditInterceptor.cs diff --git a/IRaCIS.Core.Infrastructure/_IRaCIS/IQueryablePageListExtensions.cs b/IRaCIS.Core.Infrastructure/_IRaCIS/IQueryablePageListExtensions.cs index ef697e09b..d04cc4ca8 100644 --- a/IRaCIS.Core.Infrastructure/_IRaCIS/IQueryablePageListExtensions.cs +++ b/IRaCIS.Core.Infrastructure/_IRaCIS/IQueryablePageListExtensions.cs @@ -5,44 +5,86 @@ using Microsoft.EntityFrameworkCore; using System.Linq.Dynamic.Core; using System.Collections.Generic; using System; +using System.Reflection; +using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace IRaCIS.Core.Infrastructure.Extention { public static class QueryablePageListExtensions { - //单字段排序 - public static PageOutput ToPagedList(this IQueryable source, int pageIndex, int pageSize, string defaultSortFiled = "Id", bool isAsc = true) + + //单字段排序 异步 (或者默认排序字段是空,多字段排序,传递了,就以传递的单字段为准) + public static async Task> ToPagedListAsync(this IQueryable source, PageInput pageInput, bool isMultiSortFiled = false, string[] sortArray = default, CancellationToken cancellationToken = default) { - if (pageIndex <= 0) + + if (isMultiSortFiled && sortArray == default) { - pageIndex = 1; + throw new InvalidOperationException("The sort field must be specified"); } - if (pageSize <= 0) + + + if (pageInput.PageIndex <= 0) { - pageSize = 10; + pageInput.PageIndex = 1; } - var count = source.Count(); + if (pageInput.PageSize <= 0) + { + pageInput.PageSize = 10; + } + + var count = await source.CountAsync(cancellationToken).ConfigureAwait(false); if (count == 0) { return new PageOutput() { CurrentPageData = new T[0] }; } + var propName=string.Empty; - var propName = string.IsNullOrWhiteSpace(defaultSortFiled) ? "Id" : defaultSortFiled; + if (string.IsNullOrWhiteSpace(pageInput.SortField)) + { + //没有指定,优先以Id排序,否则从属性里面随便取出来一个排序 + var propertyNameList = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(t => t.CanWrite).Select(t => t.Name).OrderBy(t => t).ToList(); - source = isAsc ? source.OrderBy(propName) : source.OrderBy(propName + " desc"); + if (propertyNameList.Count == 0) + { + throw new InvalidOperationException("no default sort field."); + } + else + { + propName= propertyNameList.Contains("Id") ? "Id" : propertyNameList.FirstOrDefault(); + } + + } + else + { + //有值,以前段传输的为主 + propName = pageInput.SortField; + } + - source = source.Skip((pageIndex - 1) * pageSize); + if (!isMultiSortFiled) + { + source = pageInput.Asc ? source.OrderBy(propName) : source.OrderBy(propName + " desc"); - var items = source - .Take(pageSize) - .ToArray(); + } + else + { + var sortString = string.Join(',', sortArray); + + source = source.OrderBy(sortString); + } + + source = source.Skip((pageInput.PageIndex - 1) * pageInput.PageSize); + var items = await source + .Take(pageInput.PageSize) + .ToArrayAsync(cancellationToken) + .ConfigureAwait(false); var pagedList = new PageOutput() { - PageIndex = pageIndex, - PageSize = pageSize, + PageIndex = pageInput.PageIndex, + PageSize = pageInput.PageSize, TotalCount = count, CurrentPageData = items }; @@ -50,8 +92,10 @@ namespace IRaCIS.Core.Infrastructure.Extention return pagedList; } + + //单字段排序 异步 - public static async Task> ToPagedListAsync(this IQueryable source, int pageNumber, int pageSize, string defaultSortFiled = "Id", bool isAsc = true, bool isMultiSortFiled = false, string[] sortArray = default, CancellationToken cancellationToken = default) + public static async Task> ToPagedListAsync(this IQueryable source, int pageNumber, int pageSize, string defaultSortFiled = "Id", bool isAsc = true, bool isMultiSortFiled = false, string[] sortArray = default) { if (isMultiSortFiled && sortArray == default) @@ -68,7 +112,7 @@ namespace IRaCIS.Core.Infrastructure.Extention pageSize = 10; } - var count = await source.CountAsync(cancellationToken).ConfigureAwait(false); + var count = await source.CountAsync().ConfigureAwait(false); if (count == 0) { @@ -90,7 +134,7 @@ namespace IRaCIS.Core.Infrastructure.Extention source = source.Skip((pageNumber - 1) * pageSize); var items = await source .Take(pageSize) - .ToArrayAsync(cancellationToken) + .ToArrayAsync() .ConfigureAwait(false); var pagedList = new PageOutput() @@ -105,85 +149,11 @@ namespace IRaCIS.Core.Infrastructure.Extention } - public static PageOutput ToPagedList(this IList source, int pageIndex, int pageSize, string defaultSortFiled = "Id", bool isAsc = true) - { - if (pageIndex <= 0) - { - pageIndex = 1; - } - if (pageSize <= 0) - { - pageSize = 10; - } - var count = source.Count(); - if (count == 0) - { - return new PageOutput() { CurrentPageData = new List() }; - } - var propName = string.IsNullOrWhiteSpace(defaultSortFiled) ? "Id" : defaultSortFiled; - - IQueryable sourceQuery = isAsc ? source.AsQueryable().OrderBy(propName) : source.AsQueryable().OrderBy(propName + " desc"); - - sourceQuery = sourceQuery.Skip((pageIndex - 1) * pageSize); - - var items = sourceQuery - .Take(pageSize) - .ToArray(); - - var pagedList = new PageOutput() - { - PageIndex = pageIndex, - PageSize = pageSize, - TotalCount = count, - CurrentPageData = items - }; - - return pagedList; - } - - //多字段排序 ["a asc", "b desc", "c asc"] - public static PageOutput ToPagedList(this IQueryable source, int pageIndex, int pageSize, string[] sortArray) - { - if (pageIndex <= 0) - { - pageIndex = 1; - } - if (pageSize <= 0) - { - pageSize = 10; - } - var count = source.Count(); - - if (count == 0) - { - return new PageOutput() { CurrentPageData = new T[0] }; - } - - var sortString = string.Join(',', sortArray); - - source.OrderBy(sortString); - - source = source.Skip((pageIndex - 1) * pageSize); - - var items = source - .Take(pageSize) - .ToArray(); - - var pagedList = new PageOutput() - { - PageIndex = pageIndex, - PageSize = pageSize, - TotalCount = count, - CurrentPageData = items - }; - - return pagedList; - } //多字段排序异步 ["a asc", "b desc", "c asc"] - public static async Task> ToPagedListAsync(this IQueryable source, int pageNumber, int pageSize, string[] sortArray, CancellationToken cancellationToken = default) + public static async Task> ToPagedListAsync(this IQueryable source, int pageNumber, int pageSize, string[] sortArray) { if (pageNumber <= 0) { @@ -194,7 +164,7 @@ namespace IRaCIS.Core.Infrastructure.Extention pageSize = 10; } - var count = await source.CountAsync(cancellationToken).ConfigureAwait(false); + var count = await source.CountAsync().ConfigureAwait(false); if (count == 0) { @@ -212,7 +182,7 @@ namespace IRaCIS.Core.Infrastructure.Extention source = source.Skip((pageNumber - 1) * pageSize); var items = await source .Take(pageSize) - .ToArrayAsync(cancellationToken) + .ToArrayAsync() .ConfigureAwait(false); var pagedList = new PageOutput() @@ -227,6 +197,127 @@ namespace IRaCIS.Core.Infrastructure.Extention } + #region 同步方法废弃 + ////单字段排序 + //public static PageOutput ToPagedList(this IQueryable source, int pageIndex, int pageSize, string defaultSortFiled = "Id", bool isAsc = true) + //{ + // if (pageIndex <= 0) + // { + // pageIndex = 1; + // } + // if (pageSize <= 0) + // { + // pageSize = 10; + // } + // var count = source.Count(); + + // if (count == 0) + // { + // return new PageOutput() { CurrentPageData = new T[0] }; + // } + + + // var propName = string.IsNullOrWhiteSpace(defaultSortFiled) ? "Id" : defaultSortFiled; + + // source = isAsc ? source.OrderBy(propName) : source.OrderBy(propName + " desc"); + + // source = source.Skip((pageIndex - 1) * pageSize); + + // var items = source + // .Take(pageSize) + // .ToArray(); + + // var pagedList = new PageOutput() + // { + // PageIndex = pageIndex, + // PageSize = pageSize, + // TotalCount = count, + // CurrentPageData = items + // }; + + // return pagedList; + //} + + //public static PageOutput ToPagedList(this IList source, int pageIndex, int pageSize, string defaultSortFiled = "Id", bool isAsc = true) + //{ + // if (pageIndex <= 0) + // { + // pageIndex = 1; + // } + // if (pageSize <= 0) + // { + // pageSize = 10; + // } + // var count = source.Count(); + + // if (count == 0) + // { + // return new PageOutput() { CurrentPageData = new List() }; + // } + + // var propName = string.IsNullOrWhiteSpace(defaultSortFiled) ? "Id" : defaultSortFiled; + + // IQueryable sourceQuery = isAsc ? source.AsQueryable().OrderBy(propName) : source.AsQueryable().OrderBy(propName + " desc"); + + // sourceQuery = sourceQuery.Skip((pageIndex - 1) * pageSize); + + // var items = sourceQuery + // .Take(pageSize) + // .ToArray(); + + // var pagedList = new PageOutput() + // { + // PageIndex = pageIndex, + // PageSize = pageSize, + // TotalCount = count, + // CurrentPageData = items + // }; + + // return pagedList; + //} + + + ////多字段排序 ["a asc", "b desc", "c asc"] + //public static PageOutput ToPagedList(this IQueryable source, int pageIndex, int pageSize, string[] sortArray) + //{ + // if (pageIndex <= 0) + // { + // pageIndex = 1; + // } + // if (pageSize <= 0) + // { + // pageSize = 10; + // } + // var count = source.Count(); + + // if (count == 0) + // { + // return new PageOutput() { CurrentPageData = new T[0] }; + // } + + // var sortString = string.Join(',', sortArray); + + // source.OrderBy(sortString); + + // source = source.Skip((pageIndex - 1) * pageSize); + + // var items = source + // .Take(pageSize) + // .ToArray(); + + // var pagedList = new PageOutput() + // { + // PageIndex = pageIndex, + // PageSize = pageSize, + // TotalCount = count, + // CurrentPageData = items + // }; + + // return pagedList; + //} + #endregion + + } } diff --git a/IRaCIS.Core.Infrastructure/_IRaCIS/Output/IResponseOutput.cs b/IRaCIS.Core.Infrastructure/_IRaCIS/Output/IResponseOutput.cs index a0edd84d0..c9f51dece 100644 --- a/IRaCIS.Core.Infrastructure/_IRaCIS/Output/IResponseOutput.cs +++ b/IRaCIS.Core.Infrastructure/_IRaCIS/Output/IResponseOutput.cs @@ -19,6 +19,8 @@ public string LocalizedInfo { get; set; } + + } /// diff --git a/IRaCIS.Core.Test/TT_Template/IRaCIS .Core.ServiceAsync.tt b/IRaCIS.Core.Test/TT_Template/IRaCIS .Core.ServiceAsync.tt index 5a1998a61..4fcd115d0 100644 --- a/IRaCIS.Core.Test/TT_Template/IRaCIS .Core.ServiceAsync.tt +++ b/IRaCIS.Core.Test/TT_Template/IRaCIS .Core.ServiceAsync.tt @@ -72,11 +72,9 @@ namespace IRaCIS.Core.Application.Service var <#=char.ToLower(tableName[0]) + tableName.Substring(1)#>Queryable = _<#=char.ToLower(tableName[0]) + tableName.Substring(1)#>Repository - .ProjectTo<<#=tableName#>View>(_mapper.ConfigurationProvider); + .ProjectTo<<#=tableName#>View>(_mapper.ConfigurationProvider); - var pageList= await <#=char.ToLower(tableName[0]) + tableName.Substring(1)#>Queryable - .ToPagedListAsync(inQuery.PageIndex, inQuery.PageSize, string.IsNullOrWhiteSpace(inQuery.SortField) ? nameof(<#=tableName#>View.Id) : inQuery.SortField, - inQuery.Asc); + var pageList= await <#=char.ToLower(tableName[0]) + tableName.Substring(1)#>Queryable.ToPagedListAsync(<#=tableName#>Query); return pageList; }