Compare commits
107 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f43535cf7 | |||
| 0697003b78 | |||
| e4b9a570d5 | |||
| 9f775df00c | |||
| 62757d7506 | |||
| 1822e201b7 | |||
| b25c72c153 | |||
| c64b826266 | |||
| fb2d2f7b2f | |||
| 92fe7bbaa9 | |||
| 75f4d5696a | |||
| 509f5ff2fc | |||
| 4f6a42aff5 | |||
| be42f52867 | |||
| 2519ad0f7a | |||
| ad4dcd294c | |||
| c251486267 | |||
| ee4fede7af | |||
| 92430c93b3 | |||
| d093c172a4 | |||
| 2740ed109a | |||
| 92facb02e8 | |||
| 718234f631 | |||
| 7be63f08b5 | |||
| 127e124993 | |||
| fbd9280b22 | |||
| b8481207fc | |||
| b1b82a016e | |||
| 768345616a | |||
| 1feb985eb7 | |||
| 496f47a4e8 | |||
| bd3d6ffe12 | |||
| 08daea6a92 | |||
| e9d720e1a5 | |||
| 5cd1454949 | |||
| d9a85b6825 | |||
| 424026866f | |||
| e5081ff568 | |||
| 3ca7d6f21b | |||
| 4faa15a219 | |||
| d61f4e89a3 | |||
| 712a1312f4 | |||
| e38739381e | |||
| ae05b73ffd | |||
| 87c9f423c9 | |||
| 2d44da15f1 | |||
| d7d7a0af55 | |||
| b3e187b53c | |||
| b0ef2dc8ab | |||
| ccf4bbdff9 | |||
| c3e36991b8 | |||
| 81f6c10f23 | |||
| 719ca071e1 | |||
| dad420a7e8 | |||
| d84aedf135 | |||
| 34f3b1607e | |||
| 7fa73e0054 | |||
| c146c2bfd2 | |||
| 2a1220899e | |||
| 874d36de28 | |||
| 0283052555 | |||
| effef5ad65 | |||
| 43d260e036 | |||
| 19708240b2 | |||
| 0999bae749 | |||
| e6bd35ae04 | |||
| 102e193ae8 | |||
| 20d557e795 | |||
| 593ab42882 | |||
| b56d256e10 | |||
| 614a3bd70e | |||
| 2eb3b04365 | |||
| 1fa3a5a181 | |||
| cd2007c4fd | |||
| 67e710eac0 | |||
| ef451d82ec | |||
| 899ebf2a30 | |||
| f233d27f96 | |||
| 9e8ab8acca | |||
| 2265387f47 | |||
| baf8f39bc6 | |||
| 3fa14d92ae | |||
| e6c577e68b | |||
| bb111dbbeb | |||
| 0df0b10a72 | |||
| 0a7ba9f0f5 | |||
| cd88990c32 | |||
| d53a1300fc | |||
| 07332ff3e1 | |||
| 8195a1cf3e | |||
| f5e5a47624 | |||
| 28608f3ecb | |||
| bb2da7ca81 | |||
| 713518a68c | |||
| bc448da297 | |||
| 8447878cb2 | |||
| 1b5a9673f6 | |||
| 27711f4184 | |||
| bb9bac1edf | |||
| 41ae2febc7 | |||
| c072c526e2 | |||
| d6bb98b84f | |||
| 42587ee59f | |||
| 62a964a3ea | |||
| 72447eb82f | |||
| 2f83c27fde | |||
| b219593f61 |
@@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
using IRaCIS.Core.Infrastructure.Extention;
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Service.BusinessFilter
|
namespace IRaCIS.Application.Services.BusinessFilter
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 统一返回前端数据包装,之前在控制器包装,现在修改为动态Api 在ResultFilter这里包装,减少重复冗余代码
|
/// 统一返回前端数据包装,之前在控制器包装,现在修改为动态Api 在ResultFilter这里包装,减少重复冗余代码
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using IRaCIS.Core.Domain.Models;
|
using IRaCIS.Core.Domain.Models;
|
||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
using IRaCIS.Core.Application.Service;
|
using IRaCIS.Application.Services;
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using IRaCIS.Core.SCP.Service;
|
using IRaCIS.Core.SCP.Service;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using IRaCIS.Core.Infra.EFCore;
|
|||||||
using Medallion.Threading;
|
using Medallion.Threading;
|
||||||
using Medallion.Threading.SqlServer;
|
using Medallion.Threading.SqlServer;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
@@ -16,12 +15,11 @@ namespace IRaCIS.Core.SCP
|
|||||||
{
|
{
|
||||||
services.AddHttpContextAccessor();
|
services.AddHttpContextAccessor();
|
||||||
services.AddScoped<IUserInfo, UserInfo>();
|
services.AddScoped<IUserInfo, UserInfo>();
|
||||||
services.AddScoped<ISaveChangesInterceptor, AuditEntityInterceptor>();
|
|
||||||
|
|
||||||
|
|
||||||
//这个注入没有成功--注入是没问题的,构造函数也只是支持参数就好,错在注入的地方不能写DbContext
|
//这个注入没有成功--注入是没问题的,构造函数也只是支持参数就好,错在注入的地方不能写DbContext
|
||||||
//Web程序中通过重用池中DbContext实例可提高高并发场景下的吞吐量, 这在概念上类似于ADO.NET Provider原生的连接池操作方式,具有节省DbContext实例化成本的优点
|
//Web程序中通过重用池中DbContext实例可提高高并发场景下的吞吐量, 这在概念上类似于ADO.NET Provider原生的连接池操作方式,具有节省DbContext实例化成本的优点
|
||||||
services.AddDbContext<IRaCISDBContext>((sp, options) =>
|
services.AddDbContextPool<IRaCISDBContext>(options =>
|
||||||
{
|
{
|
||||||
// 在控制台
|
// 在控制台
|
||||||
//public static readonly ILoggerFactory MyLoggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); });
|
//public static readonly ILoggerFactory MyLoggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); });
|
||||||
@@ -37,7 +35,6 @@ namespace IRaCIS.Core.SCP
|
|||||||
options.EnableSensitiveDataLogging();
|
options.EnableSensitiveDataLogging();
|
||||||
|
|
||||||
options.AddInterceptors(new QueryWithNoLockDbCommandInterceptor());
|
options.AddInterceptors(new QueryWithNoLockDbCommandInterceptor());
|
||||||
options.AddInterceptors(sp.GetServices<ISaveChangesInterceptor>());
|
|
||||||
|
|
||||||
options.UseProjectables();
|
options.UseProjectables();
|
||||||
|
|
||||||
|
|||||||
@@ -7,28 +7,27 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.4" />
|
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.13.0" />
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="9.0.0" />
|
||||||
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
|
<PackageReference Include="DistributedLock.Core" Version="1.0.6" />
|
||||||
<PackageReference Include="AWSSDK.S3" Version="3.7.402.7" />
|
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.4" />
|
||||||
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.400.16" />
|
<PackageReference Include="fo-dicom" Version="5.1.2" />
|
||||||
<PackageReference Include="DistributedLock.Core" Version="1.0.7" />
|
<PackageReference Include="fo-dicom.Codecs" Version="5.12.0" />
|
||||||
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.5" />
|
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.1.2" />
|
||||||
<PackageReference Include="fo-dicom" Version="5.1.3" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.4" />
|
||||||
<PackageReference Include="fo-dicom.Codecs" Version="5.14.5" />
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
|
||||||
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.1.3" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.8" />
|
|
||||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||||
<PackageReference Include="Minio" Version="6.0.3" />
|
<PackageReference Include="Minio" Version="6.0.2" />
|
||||||
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
|
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
|
||||||
<TreatAsUsed>true</TreatAsUsed>
|
<TreatAsUsed>true</TreatAsUsed>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<PackageReference Include="NewId" Version="4.0.1" />
|
||||||
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
|
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
|
||||||
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.1.1" />
|
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.0.3" />
|
||||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.3" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resourc
|
|||||||
// 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim()
|
// 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim()
|
||||||
builder.Services.AddControllers(options =>
|
builder.Services.AddControllers(options =>
|
||||||
{
|
{
|
||||||
|
//options.Filters.Add<LogActionFilter>();
|
||||||
options.Filters.Add<ModelActionFilter>();
|
options.Filters.Add<ModelActionFilter>();
|
||||||
options.Filters.Add<ProjectExceptionFilter>();
|
options.Filters.Add<ProjectExceptionFilter>();
|
||||||
options.Filters.Add<UnitOfWorkFilter>();
|
options.Filters.Add<UnitOfWorkFilter>();
|
||||||
@@ -113,11 +114,6 @@ builder.Services.AddAutoMapper(automapper =>
|
|||||||
//EF ORM QueryWithNoLock
|
//EF ORM QueryWithNoLock
|
||||||
builder.Services.AddEFSetup(_configuration);
|
builder.Services.AddEFSetup(_configuration);
|
||||||
|
|
||||||
builder.Services.AddMediator(cfg =>
|
|
||||||
{
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
//转发头设置 获取真实IP
|
//转发头设置 获取真实IP
|
||||||
builder.Services.Configure<ForwardedHeadersOptions>(options =>
|
builder.Services.Configure<ForwardedHeadersOptions>(options =>
|
||||||
|
|||||||
@@ -10,16 +10,5 @@
|
|||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Test_IRC_SCP"
|
"ASPNETCORE_ENVIRONMENT": "Test_IRC_SCP"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"Uat_IRC_SCP": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"dotnetRunMessages": true,
|
|
||||||
"launchBrowser": true,
|
|
||||||
"launchUrl": "swagger",
|
|
||||||
"applicationUrl": "http://localhost:6200",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Uat_IRC_SCP"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using IRaCIS.Core.Application.Service.BusinessFilter;
|
using IRaCIS.Application.Services.BusinessFilter;
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
@@ -26,6 +26,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
|
|
||||||
public IUserInfo _userInfo { get; set; }
|
public IUserInfo _userInfo { get; set; }
|
||||||
|
|
||||||
|
public IRepository _repository { get; set; }
|
||||||
|
|
||||||
public IStringLocalizer _localizer { get; set; }
|
public IStringLocalizer _localizer { get; set; }
|
||||||
|
|
||||||
@@ -50,6 +51,9 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
[MemberNotNull(nameof(_userInfo))]
|
[MemberNotNull(nameof(_userInfo))]
|
||||||
public IUserInfo _userInfo { get; set; }
|
public IUserInfo _userInfo { get; set; }
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(_repository))]
|
||||||
|
public IRepository _repository { get; set; }
|
||||||
|
|
||||||
[MemberNotNull(nameof(_localizer))]
|
[MemberNotNull(nameof(_localizer))]
|
||||||
public IStringLocalizer _localizer { get; set; }
|
public IStringLocalizer _localizer { get; set; }
|
||||||
|
|
||||||
@@ -71,7 +75,8 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
[MemberNotNull(nameof(_userInfo))]
|
[MemberNotNull(nameof(_userInfo))]
|
||||||
public IUserInfo _userInfo { get; set; }
|
public IUserInfo _userInfo { get; set; }
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(_repository))]
|
||||||
|
public IRepository _repository { get; set; }
|
||||||
|
|
||||||
[MemberNotNull(nameof(_localizer))]
|
[MemberNotNull(nameof(_localizer))]
|
||||||
public IStringLocalizer _localizer { get; set; }
|
public IStringLocalizer _localizer { get; set; }
|
||||||
@@ -88,6 +93,8 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
|
|
||||||
public IUserInfo _userInfo { get; set; }
|
public IUserInfo _userInfo { get; set; }
|
||||||
|
|
||||||
|
public IRepository _repository { get; set; }
|
||||||
|
|
||||||
public IStringLocalizer _localizer { get; set; }
|
public IStringLocalizer _localizer { get; set; }
|
||||||
|
|
||||||
public static IResponseOutput Null404NotFound<TEntity>(TEntity? businessObject) where TEntity : class
|
public static IResponseOutput Null404NotFound<TEntity>(TEntity? businessObject) where TEntity : class
|
||||||
|
|||||||
@@ -176,13 +176,6 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
|
|
||||||
await _SCPImageUploadRepository.AddAsync(_upload, true);
|
await _SCPImageUploadRepository.AddAsync(_upload, true);
|
||||||
|
|
||||||
|
|
||||||
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
|
||||||
//将检查设置为传输结束
|
|
||||||
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
|
|
||||||
|
|
||||||
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
|
||||||
|
|
||||||
await SendAssociationReleaseResponseAsync();
|
await SendAssociationReleaseResponseAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,11 +236,11 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
//奇怪的bug 上传的时候,用王捷修改的影像,会关闭,重新连接,导致检查id 丢失,然后状态不一致
|
//奇怪的bug 上传的时候,用王捷修改的影像,会关闭,重新连接,导致检查id 丢失,然后状态不一致
|
||||||
if (exception == null)
|
if (exception == null)
|
||||||
{
|
{
|
||||||
//var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
||||||
////将检查设置为传输结束
|
//将检查设置为传输结束
|
||||||
//await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
|
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
|
||||||
|
|
||||||
//await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.Logger.Warning($"连接关闭 {exception?.Message} {exception?.InnerException?.Message}");
|
Log.Logger.Warning($"连接关闭 {exception?.Message} {exception?.InnerException?.Message}");
|
||||||
@@ -308,7 +301,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var scpStudyId = await dicomArchiveService.ArchiveDicomFileAsync(request.Dataset, _trialId, _trialSiteId, storeRelativePath, Association.CallingAE, Association.CalledAE,fileSize);
|
var scpStudyId = await dicomArchiveService.ArchiveDicomFileAsync(request.Dataset, _trialId, _trialSiteId, storeRelativePath, Association.CallingAE, Association.CalledAE);
|
||||||
|
|
||||||
if (!_SCPStudyIdList.Contains(scpStudyId))
|
if (!_SCPStudyIdList.Contains(scpStudyId))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ using IRaCIS.Core.SCP.Service;
|
|||||||
using IRaCIS.Core.Infra.EFCore;
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
using System.Runtime.Intrinsics.X86;
|
using System.Runtime.Intrinsics.X86;
|
||||||
using Serilog.Sinks.File;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.SCP.Service
|
namespace IRaCIS.Core.SCP.Service
|
||||||
{
|
{
|
||||||
@@ -52,7 +51,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
/// <param name="dataset"></param>
|
/// <param name="dataset"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="NotImplementedException"></exception>
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
public async Task<Guid> ArchiveDicomFileAsync(DicomDataset dataset, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE,long fileSize)
|
public async Task<Guid> ArchiveDicomFileAsync(DicomDataset dataset, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE)
|
||||||
{
|
{
|
||||||
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
|
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
|
||||||
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
|
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
|
||||||
@@ -271,10 +270,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
WindowCenter = dataset.GetSingleValueOrDefault(DicomTag.WindowCenter, string.Empty),
|
WindowCenter = dataset.GetSingleValueOrDefault(DicomTag.WindowCenter, string.Empty),
|
||||||
WindowWidth = dataset.GetSingleValueOrDefault(DicomTag.WindowWidth, string.Empty),
|
WindowWidth = dataset.GetSingleValueOrDefault(DicomTag.WindowWidth, string.Empty),
|
||||||
|
|
||||||
Path = fileRelativePath,
|
Path = fileRelativePath
|
||||||
|
|
||||||
FileSize= fileSize,
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
++findStudy.InstanceCount;
|
++findStudy.InstanceCount;
|
||||||
@@ -304,7 +300,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new SCPInstance() { Path = fileRelativePath,FileSize=fileSize });
|
await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new SCPInstance() { Path = fileRelativePath });
|
||||||
}
|
}
|
||||||
|
|
||||||
//await _studyRepository.SaveChangesAsync();
|
//await _studyRepository.SaveChangesAsync();
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
{
|
{
|
||||||
public interface IDicomArchiveService
|
public interface IDicomArchiveService
|
||||||
{
|
{
|
||||||
Task<Guid> ArchiveDicomFileAsync(DicomDataset dicomDataset,Guid trialId,Guid trialSiteId, string fileRelativePath,string callingAE,string calledAE,long fileSize);
|
Task<Guid> ArchiveDicomFileAsync(DicomDataset dicomDataset,Guid trialId,Guid trialSiteId, string fileRelativePath,string callingAE,string calledAE);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+124
-452
@@ -1,139 +1,102 @@
|
|||||||
using AlibabaCloud.SDK.Sts20150401;
|
using Aliyun.OSS;
|
||||||
using Aliyun.OSS;
|
|
||||||
using Amazon;
|
|
||||||
using Amazon.Runtime;
|
|
||||||
using Amazon.S3;
|
|
||||||
using Amazon.S3.Model;
|
|
||||||
using Amazon.SecurityToken;
|
|
||||||
using Amazon.SecurityToken.Model;
|
|
||||||
using IRaCIS.Core.Infrastructure;
|
using IRaCIS.Core.Infrastructure;
|
||||||
using IRaCIS.Core.Infrastructure.NewtonsoftJson;
|
using Microsoft.Extensions.Hosting;
|
||||||
using MassTransit;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Minio;
|
|
||||||
using Minio.DataModel.Args;
|
using Minio.DataModel.Args;
|
||||||
using System.Reactive.Linq;
|
using Minio;
|
||||||
|
using SharpCompress.Common;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.AccessControl;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace IRaCIS.Core.SCP;
|
namespace IRaCIS.Core.SCP
|
||||||
|
|
||||||
#region 绑定和返回模型
|
|
||||||
|
|
||||||
[LowerCamelCaseJson]
|
|
||||||
public class MinIOOptions : AWSOptions
|
|
||||||
{
|
{
|
||||||
public int Port { get; set; }
|
public class MinIOOptions : AWSOptions
|
||||||
|
{
|
||||||
|
public int port { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class AWSOptions
|
||||||
|
{
|
||||||
|
public string endPoint { get; set; }
|
||||||
|
public bool useSSL { get; set; }
|
||||||
|
public string accessKey { get; set; }
|
||||||
|
public string secretKey { get; set; }
|
||||||
|
public string bucketName { get; set; }
|
||||||
|
public string viewEndpoint { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class AWSOptions
|
public class AliyunOSSOptions
|
||||||
{
|
{
|
||||||
public string EndPoint { get; set; }
|
public string regionId { get; set; }
|
||||||
public bool UseSSL { get; set; }
|
public string accessKeyId { get; set; }
|
||||||
public string AccessKeyId { get; set; }
|
public string accessKeySecret { get; set; }
|
||||||
public string RoleArn { get; set; }
|
|
||||||
public string SecretAccessKey { get; set; }
|
|
||||||
public string BucketName { get; set; }
|
|
||||||
public string ViewEndpoint { get; set; }
|
|
||||||
public int DurationSeconds { get; set; }
|
|
||||||
public string Region { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AliyunOSSOptions
|
public string internalEndpoint { get; set; }
|
||||||
{
|
|
||||||
public string RegionId { get; set; }
|
|
||||||
public string AccessKeyId { get; set; }
|
|
||||||
public string AccessKeySecret { get; set; }
|
|
||||||
|
|
||||||
public string InternalEndpoint { get; set; }
|
public string endPoint { get; set; }
|
||||||
|
public string bucketName { get; set; }
|
||||||
|
|
||||||
public string EndPoint { get; set; }
|
public string roleArn { get; set; }
|
||||||
public string BucketName { get; set; }
|
|
||||||
|
|
||||||
public string RoleArn { get; set; }
|
public string region { get; set; }
|
||||||
|
|
||||||
public string Region { get; set; }
|
public string viewEndpoint { get; set; }
|
||||||
|
|
||||||
public string ViewEndpoint { get; set; }
|
}
|
||||||
|
|
||||||
public int DurationSeconds { get; set; }
|
public class ObjectStoreServiceOptions
|
||||||
|
{
|
||||||
|
public string ObjectStoreUse { get; set; }
|
||||||
|
public AliyunOSSOptions AliyunOSS { get; set; }
|
||||||
|
public MinIOOptions MinIO { get; set; }
|
||||||
|
|
||||||
|
public AWSOptions AWS { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
public class ObjectStoreDTO
|
||||||
|
{
|
||||||
public class ObjectStoreServiceOptions
|
|
||||||
{
|
|
||||||
public string ObjectStoreUse { get; set; }
|
public string ObjectStoreUse { get; set; }
|
||||||
|
|
||||||
public AliyunOSSOptions AliyunOSS { get; set; }
|
public AliyunOSSOptions AliyunOSS { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public MinIOOptions MinIO { get; set; }
|
public MinIOOptions MinIO { get; set; }
|
||||||
|
|
||||||
public AWSOptions AWS { get; set; }
|
public AWSOptions AWS { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ObjectStoreDTO
|
public class AliyunOSSTempToken
|
||||||
{
|
{
|
||||||
public string ObjectStoreUse { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public AliyunOSSTempToken AliyunOSS { get; set; }
|
|
||||||
|
|
||||||
public MinIOOptions MinIO { get; set; }
|
|
||||||
|
|
||||||
public AWSTempToken AWS { get; set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[LowerCamelCaseJson]
|
|
||||||
public class AliyunOSSTempToken
|
|
||||||
{
|
|
||||||
public string AccessKeyId { get; set; }
|
public string AccessKeyId { get; set; }
|
||||||
public string AccessKeySecret { get; set; }
|
public string AccessKeySecret { get; set; }
|
||||||
|
|
||||||
public string EndPoint { get; set; }
|
|
||||||
public string BucketName { get; set; }
|
|
||||||
|
|
||||||
public string Region { get; set; }
|
|
||||||
|
|
||||||
public string ViewEndpoint { get; set; }
|
|
||||||
|
|
||||||
public string SecurityToken { get; set; }
|
public string SecurityToken { get; set; }
|
||||||
public DateTime Expiration { get; set; }
|
public string Expiration { get; set; }
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[LowerCamelCaseJson]
|
|
||||||
public class AWSTempToken
|
|
||||||
{
|
|
||||||
public string Region { get; set; }
|
public string Region { get; set; }
|
||||||
public string SessionToken { get; set; }
|
|
||||||
public string EndPoint { get; set; }
|
|
||||||
public string AccessKeyId { get; set; }
|
|
||||||
public string SecretAccessKey { get; set; }
|
|
||||||
public string BucketName { get; set; }
|
public string BucketName { get; set; }
|
||||||
public string ViewEndpoint { get; set; }
|
public string ViewEndpoint { get; set; }
|
||||||
public DateTime Expiration { get; set; }
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public enum ObjectStoreUse
|
|
||||||
{
|
|
||||||
|
public enum ObjectStoreUse
|
||||||
|
{
|
||||||
AliyunOSS = 0,
|
AliyunOSS = 0,
|
||||||
MinIO = 1,
|
MinIO = 1,
|
||||||
AWS = 2,
|
AWS = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
public interface IOSSService
|
||||||
|
{
|
||||||
// aws 参考链接 https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3/S3/S3_Basics
|
|
||||||
|
|
||||||
public interface IOSSService
|
|
||||||
{
|
|
||||||
public Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true);
|
public Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true);
|
||||||
public Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true);
|
public Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true);
|
||||||
|
|
||||||
@@ -143,29 +106,19 @@ public interface IOSSService
|
|||||||
|
|
||||||
public Task<string> GetSignedUrl(string ossRelativePath);
|
public Task<string> GetSignedUrl(string ossRelativePath);
|
||||||
|
|
||||||
public Task DeleteFromPrefix(string prefix);
|
}
|
||||||
|
|
||||||
public ObjectStoreDTO GetObjectStoreTempToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class OSSService : IOSSService
|
public class OSSService : IOSSService
|
||||||
{
|
{
|
||||||
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
|
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
|
||||||
|
|
||||||
private AliyunOSSTempToken AliyunOSSTempToken { get; set; }
|
|
||||||
|
|
||||||
private AWSTempToken AWSTempToken { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options)
|
public OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options)
|
||||||
{
|
{
|
||||||
ObjectStoreServiceOptions = options.CurrentValue;
|
ObjectStoreServiceOptions = options.CurrentValue;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
|
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -176,9 +129,9 @@ public class OSSService : IOSSService
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true)
|
public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
|
||||||
|
|
||||||
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}";
|
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}";
|
||||||
|
//var ossRelativePath = $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}";
|
||||||
|
//var ossRelativePath = oosFolderPath + "/" + fileRealName;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -195,12 +148,12 @@ public class OSSService : IOSSService
|
|||||||
{
|
{
|
||||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||||
|
|
||||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.endPoint : aliConfig.internalEndpoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 上传文件
|
// 上传文件
|
||||||
var result = _ossClient.PutObject(aliConfig.BucketName, ossRelativePath, memoryStream);
|
var result = _ossClient.PutObject(aliConfig.bucketName, ossRelativePath, memoryStream);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||||
@@ -208,12 +161,12 @@ public class OSSService : IOSSService
|
|||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var putObjectArgs = new PutObjectArgs()
|
var putObjectArgs = new PutObjectArgs()
|
||||||
.WithBucket(minIOConfig.BucketName)
|
.WithBucket(minIOConfig.bucketName)
|
||||||
.WithObject(ossRelativePath)
|
.WithObject(ossRelativePath)
|
||||||
.WithStreamData(memoryStream)
|
.WithStreamData(memoryStream)
|
||||||
.WithObjectSize(memoryStream.Length);
|
.WithObjectSize(memoryStream.Length);
|
||||||
@@ -222,29 +175,20 @@ public class OSSService : IOSSService
|
|||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||||
{
|
{
|
||||||
var awsConfig = ObjectStoreServiceOptions.AWS;
|
var minIOConfig = ObjectStoreServiceOptions.AWS;
|
||||||
|
|
||||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
|
||||||
|
|
||||||
|
|
||||||
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
|
||||||
|
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||||
|
.Build();
|
||||||
|
|
||||||
//提供awsEndPoint(域名)进行访问配置
|
var putObjectArgs = new PutObjectArgs()
|
||||||
var clientConfig = new AmazonS3Config
|
.WithBucket(minIOConfig.bucketName)
|
||||||
{
|
.WithObject(ossRelativePath)
|
||||||
RegionEndpoint = RegionEndpoint.USEast1,
|
.WithStreamData(memoryStream)
|
||||||
UseHttp = true,
|
.WithObjectSize(memoryStream.Length);
|
||||||
};
|
|
||||||
|
|
||||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
await minioClient.PutObjectAsync(putObjectArgs);
|
||||||
|
|
||||||
var putObjectRequest = new Amazon.S3.Model.PutObjectRequest()
|
|
||||||
{
|
|
||||||
BucketName = awsConfig.BucketName,
|
|
||||||
InputStream = memoryStream,
|
|
||||||
Key = ossRelativePath,
|
|
||||||
};
|
|
||||||
|
|
||||||
await amazonS3Client.PutObjectAsync(putObjectRequest);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -272,26 +216,26 @@ public class OSSService : IOSSService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="localFilePath"></param>
|
/// <param name="localFilePath"></param>
|
||||||
/// <param name="oosFolderPath"></param>
|
/// <param name="oosFolderPath"></param>
|
||||||
/// <param name="isFileNameAddGuid"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="BusinessValidationFailedException"></exception>
|
/// <exception cref="BusinessValidationFailedException"></exception>
|
||||||
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
|
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
|
||||||
|
|
||||||
var localFileName = Path.GetFileName(localFilePath);
|
var localFileName = Path.GetFileName(localFilePath);
|
||||||
|
|
||||||
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{localFileName}" : $"{oosFolderPath}/{localFileName}";
|
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{localFileName}" : $"{oosFolderPath}/{localFileName}";
|
||||||
|
|
||||||
|
|
||||||
|
//var ossRelativePath = oosFolderPath + "/" + localFileName;
|
||||||
|
|
||||||
|
|
||||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||||
{
|
{
|
||||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||||
|
|
||||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.endPoint : aliConfig.internalEndpoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);
|
||||||
|
|
||||||
// 上传文件
|
// 上传文件
|
||||||
var result = _ossClient.PutObject(aliConfig.BucketName, ossRelativePath, localFilePath);
|
var result = _ossClient.PutObject(aliConfig.bucketName, ossRelativePath, localFilePath);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||||
@@ -299,12 +243,12 @@ public class OSSService : IOSSService
|
|||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var putObjectArgs = new PutObjectArgs()
|
var putObjectArgs = new PutObjectArgs()
|
||||||
.WithBucket(minIOConfig.BucketName)
|
.WithBucket(minIOConfig.bucketName)
|
||||||
.WithObject(ossRelativePath)
|
.WithObject(ossRelativePath)
|
||||||
.WithFileName(localFilePath);
|
.WithFileName(localFilePath);
|
||||||
|
|
||||||
@@ -312,29 +256,19 @@ public class OSSService : IOSSService
|
|||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||||
{
|
{
|
||||||
var awsConfig = ObjectStoreServiceOptions.AWS;
|
var minIOConfig = ObjectStoreServiceOptions.AWS;
|
||||||
|
|
||||||
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
|
|
||||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
|
||||||
|
|
||||||
//提供awsEndPoint(域名)进行访问配置
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
|
||||||
var clientConfig = new AmazonS3Config
|
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||||
{
|
.Build();
|
||||||
RegionEndpoint = RegionEndpoint.USEast1,
|
|
||||||
UseHttp = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
var putObjectArgs = new PutObjectArgs()
|
||||||
|
.WithBucket(minIOConfig.bucketName)
|
||||||
var putObjectRequest = new Amazon.S3.Model.PutObjectRequest()
|
.WithObject(ossRelativePath)
|
||||||
{
|
.WithFileName(localFilePath);
|
||||||
BucketName = awsConfig.BucketName,
|
|
||||||
FilePath = localFilePath,
|
|
||||||
Key = ossRelativePath,
|
|
||||||
};
|
|
||||||
|
|
||||||
await amazonS3Client.PutObjectAsync(putObjectRequest);
|
|
||||||
|
|
||||||
|
await minioClient.PutObjectAsync(putObjectArgs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -347,7 +281,6 @@ public class OSSService : IOSSService
|
|||||||
|
|
||||||
public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
|
public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
|
||||||
|
|
||||||
ossRelativePath = ossRelativePath.TrimStart('/');
|
ossRelativePath = ossRelativePath.TrimStart('/');
|
||||||
try
|
try
|
||||||
@@ -358,10 +291,10 @@ public class OSSService : IOSSService
|
|||||||
{
|
{
|
||||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||||
|
|
||||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.endPoint : aliConfig.internalEndpoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);
|
||||||
|
|
||||||
// 上传文件
|
// 上传文件
|
||||||
var result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);
|
var result = _ossClient.GetObject(aliConfig.bucketName, ossRelativePath);
|
||||||
|
|
||||||
// 将下载的文件流保存到本地文件
|
// 将下载的文件流保存到本地文件
|
||||||
using (var fs = File.OpenWrite(localFilePath))
|
using (var fs = File.OpenWrite(localFilePath))
|
||||||
@@ -375,12 +308,12 @@ public class OSSService : IOSSService
|
|||||||
{
|
{
|
||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var getObjectArgs = new GetObjectArgs()
|
var getObjectArgs = new GetObjectArgs()
|
||||||
.WithBucket(minIOConfig.BucketName)
|
.WithBucket(minIOConfig.bucketName)
|
||||||
.WithObject(ossRelativePath)
|
.WithObject(ossRelativePath)
|
||||||
.WithFile(localFilePath);
|
.WithFile(localFilePath);
|
||||||
|
|
||||||
@@ -389,30 +322,18 @@ public class OSSService : IOSSService
|
|||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||||
{
|
{
|
||||||
var awsConfig = ObjectStoreServiceOptions.AWS;
|
var minIOConfig = ObjectStoreServiceOptions.AWS;
|
||||||
|
|
||||||
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
|
||||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||||
|
.Build();
|
||||||
//提供awsEndPoint(域名)进行访问配置
|
|
||||||
var clientConfig = new AmazonS3Config
|
|
||||||
{
|
|
||||||
RegionEndpoint = RegionEndpoint.USEast1,
|
|
||||||
UseHttp = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
|
||||||
|
|
||||||
var getObjectArgs = new Amazon.S3.Model.GetObjectRequest()
|
|
||||||
{
|
|
||||||
BucketName = awsConfig.BucketName,
|
|
||||||
Key = ossRelativePath,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
await (await amazonS3Client.GetObjectAsync(getObjectArgs)).WriteResponseStreamToFileAsync(localFilePath, true, CancellationToken.None);
|
|
||||||
|
|
||||||
|
var getObjectArgs = new GetObjectArgs()
|
||||||
|
.WithBucket(minIOConfig.bucketName)
|
||||||
|
.WithObject(ossRelativePath)
|
||||||
|
.WithFile(localFilePath);
|
||||||
|
|
||||||
|
await minioClient.GetObjectAsync(getObjectArgs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -433,8 +354,6 @@ public class OSSService : IOSSService
|
|||||||
|
|
||||||
public async Task<string> GetSignedUrl(string ossRelativePath)
|
public async Task<string> GetSignedUrl(string ossRelativePath)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
|
||||||
|
|
||||||
ossRelativePath = ossRelativePath.TrimStart('/');
|
ossRelativePath = ossRelativePath.TrimStart('/');
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -444,10 +363,10 @@ public class OSSService : IOSSService
|
|||||||
{
|
{
|
||||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||||
|
|
||||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.endPoint : aliConfig.internalEndpoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);
|
||||||
|
|
||||||
// 生成签名URL。
|
// 生成签名URL。
|
||||||
var req = new GeneratePresignedUriRequest(aliConfig.BucketName, ossRelativePath, SignHttpMethod.Get)
|
var req = new GeneratePresignedUriRequest(aliConfig.bucketName, ossRelativePath, SignHttpMethod.Get)
|
||||||
{
|
{
|
||||||
// 设置签名URL过期时间,默认值为3600秒。
|
// 设置签名URL过期时间,默认值为3600秒。
|
||||||
Expiration = DateTime.Now.AddHours(1),
|
Expiration = DateTime.Now.AddHours(1),
|
||||||
@@ -461,13 +380,13 @@ public class OSSService : IOSSService
|
|||||||
{
|
{
|
||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
|
||||||
var args = new PresignedGetObjectArgs()
|
var args = new PresignedGetObjectArgs()
|
||||||
.WithBucket(minIOConfig.BucketName)
|
.WithBucket(minIOConfig.bucketName)
|
||||||
.WithObject(ossRelativePath)
|
.WithObject(ossRelativePath)
|
||||||
.WithExpiry(3600)
|
.WithExpiry(3600)
|
||||||
/*.WithHeaders(reqParams)*/;
|
/*.WithHeaders(reqParams)*/;
|
||||||
@@ -484,27 +403,18 @@ public class OSSService : IOSSService
|
|||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||||
{
|
{
|
||||||
var awsConfig = ObjectStoreServiceOptions.AWS;
|
var minIOConfig = ObjectStoreServiceOptions.AWS;
|
||||||
|
|
||||||
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
|
||||||
|
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||||
|
.Build();
|
||||||
|
|
||||||
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
|
var args = new PresignedGetObjectArgs()
|
||||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
.WithBucket(minIOConfig.bucketName)
|
||||||
|
.WithObject(ossRelativePath)
|
||||||
|
.WithExpiry(3600);
|
||||||
|
|
||||||
//提供awsEndPoint(域名)进行访问配置
|
var presignedUrl = await minioClient.PresignedGetObjectAsync(args);
|
||||||
var clientConfig = new AmazonS3Config
|
|
||||||
{
|
|
||||||
RegionEndpoint = RegionEndpoint.USEast1,
|
|
||||||
UseHttp = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
|
||||||
|
|
||||||
var presignedUrl = await amazonS3Client.GetPreSignedURLAsync(new GetPreSignedUrlRequest()
|
|
||||||
{
|
|
||||||
BucketName = awsConfig.BucketName,
|
|
||||||
Key = ossRelativePath,
|
|
||||||
Expires = DateTime.UtcNow.AddMinutes(120)
|
|
||||||
});
|
|
||||||
|
|
||||||
Uri uri = new Uri(presignedUrl);
|
Uri uri = new Uri(presignedUrl);
|
||||||
|
|
||||||
@@ -525,246 +435,8 @@ public class OSSService : IOSSService
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 删除某个目录的文件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="prefix"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task DeleteFromPrefix(string prefix)
|
|
||||||
{
|
|
||||||
GetObjectStoreTempToken();
|
|
||||||
|
|
||||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
|
||||||
{
|
|
||||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
|
||||||
|
|
||||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
|
||||||
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ObjectListing objectListing = null;
|
|
||||||
string nextMarker = null;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// 使用 prefix 模拟目录结构,设置 MaxKeys 和 NextMarker
|
|
||||||
objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(aliConfig.BucketName)
|
|
||||||
{
|
|
||||||
Prefix = prefix,
|
|
||||||
MaxKeys = 1000,
|
|
||||||
Marker = nextMarker
|
|
||||||
});
|
|
||||||
|
|
||||||
List<string> keys = objectListing.ObjectSummaries.Select(t => t.Key).ToList();
|
|
||||||
|
|
||||||
// 删除获取到的文件
|
|
||||||
if (keys.Count > 0)
|
|
||||||
{
|
|
||||||
_ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(aliConfig.BucketName, keys, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置 NextMarker 以获取下一页的数据
|
|
||||||
nextMarker = objectListing.NextMarker;
|
|
||||||
|
|
||||||
} while (objectListing.IsTruncated);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Error: {ex.Message}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
|
||||||
{
|
|
||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
|
||||||
|
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
|
|
||||||
var listArgs = new ListObjectsArgs().WithBucket(minIOConfig.BucketName).WithPrefix(prefix).WithRecursive(true);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 创建一个空列表用于存储对象键
|
|
||||||
var objects = new List<string>();
|
|
||||||
|
|
||||||
// 使用 await foreach 来异步迭代对象列表
|
|
||||||
await foreach (var item in minioClient.ListObjectsEnumAsync(listArgs))
|
|
||||||
{
|
|
||||||
objects.Add(item.Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (objects.Count > 0)
|
|
||||||
{
|
|
||||||
var objArgs = new RemoveObjectsArgs()
|
|
||||||
.WithBucket(minIOConfig.BucketName)
|
|
||||||
.WithObjects(objects);
|
|
||||||
|
|
||||||
// 删除对象
|
|
||||||
await minioClient.RemoveObjectsAsync(objArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
|
||||||
{
|
|
||||||
|
|
||||||
var awsConfig = ObjectStoreServiceOptions.AWS;
|
|
||||||
|
|
||||||
|
|
||||||
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
|
|
||||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
|
||||||
|
|
||||||
//提供awsEndPoint(域名)进行访问配置
|
|
||||||
var clientConfig = new AmazonS3Config
|
|
||||||
{
|
|
||||||
RegionEndpoint = RegionEndpoint.USEast1,
|
|
||||||
UseHttp = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
|
||||||
|
|
||||||
// 列出指定前缀下的所有对象
|
|
||||||
var listObjectsRequest = new ListObjectsV2Request
|
|
||||||
{
|
|
||||||
BucketName = awsConfig.BucketName,
|
|
||||||
Prefix = prefix
|
|
||||||
};
|
|
||||||
|
|
||||||
var listObjectsResponse = await amazonS3Client.ListObjectsV2Async(listObjectsRequest);
|
|
||||||
|
|
||||||
if (listObjectsResponse.S3Objects.Count > 0)
|
|
||||||
{
|
|
||||||
// 准备删除请求
|
|
||||||
var deleteObjectsRequest = new Amazon.S3.Model.DeleteObjectsRequest
|
|
||||||
{
|
|
||||||
BucketName = awsConfig.BucketName,
|
|
||||||
Objects = new List<KeyVersion>()
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var s3Object in listObjectsResponse.S3Objects)
|
|
||||||
{
|
|
||||||
deleteObjectsRequest.Objects.Add(new KeyVersion
|
|
||||||
{
|
|
||||||
Key = s3Object.Key
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 批量删除对象
|
|
||||||
var deleteObjectsResponse = await amazonS3Client.DeleteObjectsAsync(deleteObjectsRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public ObjectStoreDTO GetObjectStoreTempToken()
|
|
||||||
{
|
|
||||||
|
|
||||||
var ossOptions = ObjectStoreServiceOptions.AliyunOSS;
|
|
||||||
|
|
||||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
|
||||||
{
|
|
||||||
var client = new Client(new AlibabaCloud.OpenApiClient.Models.Config()
|
|
||||||
{
|
|
||||||
AccessKeyId = ossOptions.AccessKeyId,
|
|
||||||
AccessKeySecret = ossOptions.AccessKeySecret,
|
|
||||||
//AccessKeyId = "LTAI5tJV76pYX5yPg1N9QVE8",
|
|
||||||
//AccessKeySecret = "roRNLa9YG1of4pYruJGCNKBXEWTAWa",
|
|
||||||
|
|
||||||
Endpoint = "sts.cn-hangzhou.aliyuncs.com"
|
|
||||||
});
|
|
||||||
|
|
||||||
var assumeRoleRequest = new AlibabaCloud.SDK.Sts20150401.Models.AssumeRoleRequest();
|
|
||||||
// 将<YOUR_ROLE_SESSION_NAME>设置为自定义的会话名称,例如oss-role-session。
|
|
||||||
assumeRoleRequest.RoleSessionName = $"session-name-{NewId.NextGuid()}";
|
|
||||||
// 将<YOUR_ROLE_ARN>替换为拥有上传文件到指定OSS Bucket权限的RAM角色的ARN。
|
|
||||||
assumeRoleRequest.RoleArn = ossOptions.RoleArn;
|
|
||||||
//assumeRoleRequest.RoleArn = "acs:ram::1899121822495495:role/webdirect";
|
|
||||||
assumeRoleRequest.DurationSeconds = ossOptions.DurationSeconds;
|
|
||||||
var runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions();
|
|
||||||
var response = client.AssumeRoleWithOptions(assumeRoleRequest, runtime);
|
|
||||||
var credentials = response.Body.Credentials;
|
|
||||||
|
|
||||||
var tempToken = new AliyunOSSTempToken()
|
|
||||||
{
|
|
||||||
AccessKeyId = credentials.AccessKeyId,
|
|
||||||
AccessKeySecret = credentials.AccessKeySecret,
|
|
||||||
|
|
||||||
//转为服务器时区,最后统一转为客户端时区
|
|
||||||
Expiration = TimeZoneInfo.ConvertTimeFromUtc(DateTime.Parse(credentials.Expiration), TimeZoneInfo.Local),
|
|
||||||
SecurityToken = credentials.SecurityToken,
|
|
||||||
|
|
||||||
|
|
||||||
Region = ossOptions.Region,
|
|
||||||
BucketName = ossOptions.BucketName,
|
|
||||||
EndPoint = ossOptions.EndPoint,
|
|
||||||
ViewEndpoint = ossOptions.ViewEndpoint,
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
AliyunOSSTempToken = tempToken;
|
|
||||||
|
|
||||||
return new ObjectStoreDTO() { ObjectStoreUse = ObjectStoreServiceOptions.ObjectStoreUse, AliyunOSS = tempToken };
|
|
||||||
}
|
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
|
||||||
{
|
|
||||||
return new ObjectStoreDTO() { ObjectStoreUse = ObjectStoreServiceOptions.ObjectStoreUse, MinIO = ObjectStoreServiceOptions.MinIO };
|
|
||||||
}
|
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
|
||||||
{
|
|
||||||
var awsOptions = ObjectStoreServiceOptions.AWS;
|
|
||||||
|
|
||||||
//aws 临时凭证
|
|
||||||
// 创建 STS 客户端
|
|
||||||
var stsClient = new AmazonSecurityTokenServiceClient(awsOptions.AccessKeyId, awsOptions.SecretAccessKey);
|
|
||||||
|
|
||||||
// 使用 AssumeRole 请求临时凭证
|
|
||||||
var assumeRoleRequest = new AssumeRoleRequest
|
|
||||||
{
|
|
||||||
|
|
||||||
RoleArn = awsOptions.RoleArn, // 角色 ARN
|
|
||||||
RoleSessionName = $"session-name-{NewId.NextGuid()}",
|
|
||||||
DurationSeconds = awsOptions.DurationSeconds // 临时凭证有效期
|
|
||||||
};
|
|
||||||
|
|
||||||
var assumeRoleResponse = stsClient.AssumeRoleAsync(assumeRoleRequest).Result;
|
|
||||||
|
|
||||||
var credentials = assumeRoleResponse.Credentials;
|
|
||||||
|
|
||||||
var tempToken = new AWSTempToken()
|
|
||||||
{
|
|
||||||
AccessKeyId = credentials.AccessKeyId,
|
|
||||||
SecretAccessKey = credentials.SecretAccessKey,
|
|
||||||
SessionToken = credentials.SessionToken,
|
|
||||||
Expiration = credentials.Expiration,
|
|
||||||
Region = awsOptions.Region,
|
|
||||||
BucketName = awsOptions.BucketName,
|
|
||||||
EndPoint = awsOptions.EndPoint,
|
|
||||||
ViewEndpoint = awsOptions.ViewEndpoint,
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
AWSTempToken = tempToken;
|
|
||||||
return new ObjectStoreDTO() { ObjectStoreUse = ObjectStoreServiceOptions.ObjectStoreUse, AWS = tempToken };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,29 +9,54 @@
|
|||||||
"ObjectStoreService": {
|
"ObjectStoreService": {
|
||||||
"ObjectStoreUse": "AliyunOSS",
|
"ObjectStoreUse": "AliyunOSS",
|
||||||
"AliyunOSS": {
|
"AliyunOSS": {
|
||||||
"RegionId": "cn-shanghai",
|
"regionId": "cn-shanghai",
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
"internalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
"endpoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||||
"AccessKeyId": "LTAI5tNRTsqL6aWmHkDmTwoH",
|
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
|
||||||
"AccessKeySecret": "7mtGz3qrYWI6JMMBZiLeC119VWicZH",
|
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
|
||||||
"RoleArn": "acs:ram::1899121822495495:role/irc-oss-access",
|
"bucketName": "zy-irc-store",
|
||||||
"BucketName": "zy-irc-store",
|
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
|
||||||
"ViewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
|
"viewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
|
||||||
"Region": "oss-cn-shanghai",
|
"region": "oss-cn-shanghai"
|
||||||
"DurationSeconds": 7200
|
},
|
||||||
|
|
||||||
|
"MinIO": {
|
||||||
|
"endpoint": "http://192.168.3.68",
|
||||||
|
"port": "8001",
|
||||||
|
"useSSL": false,
|
||||||
|
"accessKey": "IDFkwEpWej0b4DtiuThL",
|
||||||
|
"secretKey": "Lhuu83yMhVwu7c1SnjvGY6lq74jzpYqifK6Qtj4h",
|
||||||
|
"bucketName": "test"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"RemoteNew": "Server=prod_mssql_standard,1433;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
|
"RemoteNew": "Server=us-prod-mssql-service,1433;Database=US_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
"Hangfire": "Server=prod_mssql_standard,1433;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
|
"Hangfire": "Server=us-prod-mssql-service,1433;Database=US_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||||
},
|
},
|
||||||
|
|
||||||
"DicomSCPServiceConfig": {
|
"BasicSystemConfig": {
|
||||||
"CalledAEList": [
|
|
||||||
"STORESCP"
|
"OpenUserComplexPassword": true,
|
||||||
],
|
|
||||||
"ServerPort": 11112
|
"OpenSignDocumentBeforeWork": true,
|
||||||
|
|
||||||
|
"OpenTrialRelationDelete": true,
|
||||||
|
|
||||||
|
"OpenLoginLimit": true,
|
||||||
|
"LoginMaxFailCount": 5,
|
||||||
|
|
||||||
|
"LoginFailLockMinutes": 30
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
"SystemEmailSendConfig": {
|
||||||
|
"Port": 465,
|
||||||
|
"Host": "smtp.qiye.aliyun.com",
|
||||||
|
"FromEmail": "study@extimaging.com",
|
||||||
|
"FromName": "研究单位阅片系统",
|
||||||
|
"AuthorizationCode": "zhanying123",
|
||||||
|
"SiteUrl": "https://study.extimaging.com/login"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,22 +6,48 @@
|
|||||||
"Microsoft.Hosting.Lifetime": "Information"
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
<<<<<<<< HEAD:IRaCIS.Core.API/appsettings.US_Test_IRC.json
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"RemoteNew": "Server=106.14.89.110,1435;Database=Test_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
|
"Hangfire": "Server=106.14.89.110,1435;Database=Test_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||||
|
},
|
||||||
|
|
||||||
|
"ObjectStoreService": {
|
||||||
|
|
||||||
|
"ObjectStoreUse": "MinIO",
|
||||||
|
========
|
||||||
"ObjectStoreService": {
|
"ObjectStoreService": {
|
||||||
"ObjectStoreUse": "AliyunOSS",
|
"ObjectStoreUse": "AliyunOSS",
|
||||||
|
>>>>>>>> Test_IRC_Net8:IRC.Core.SCP/appsettings.Test_IRC_SCP.json
|
||||||
"AliyunOSS": {
|
"AliyunOSS": {
|
||||||
"RegionId": "cn-shanghai",
|
"regionId": "cn-shanghai",
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
"internalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
"endPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||||
"AccessKeyId": "LTAI5tRRZehUp2V9pyTPtAJm",
|
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
|
||||||
"AccessKeySecret": "FLizxkHsMm4CGYHtkV8E3PNJJZU7oV",
|
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
|
||||||
"RoleArn": "acs:ram::1899121822495495:role/dev-oss-access",
|
"bucketName": "zy-irc-test-store",
|
||||||
"BucketName": "zy-irc-test-store",
|
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
|
||||||
"ViewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
|
"viewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
|
||||||
"Region": "oss-cn-shanghai",
|
"region": "oss-cn-shanghai"
|
||||||
"DurationSeconds": 7200
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"MinIO": {
|
"MinIO": {
|
||||||
|
<<<<<<<< HEAD:IRaCIS.Core.API/appsettings.US_Test_IRC.json
|
||||||
|
//"endPoint": "hir-oss.uat.extimaging.com",
|
||||||
|
//"port": "443",
|
||||||
|
//"useSSL": true,
|
||||||
|
//"viewEndpoint": "https://hir-oss.uat.extimaging.com/hir-uat",
|
||||||
|
|
||||||
|
"endPoint": "47.117.164.182",
|
||||||
|
"port": "9001",
|
||||||
|
"useSSL": false,
|
||||||
|
"viewEndpoint": "http://47.117.164.182:9001/test-irc-us",
|
||||||
|
|
||||||
|
"accessKey": "b9Ul0e98xPzt6PwRXA1Q",
|
||||||
|
"secretKey": "DzMaU2L4OXl90uytwOmDXF2encN0Jf4Nxu2XkYqQ",
|
||||||
|
"bucketName": "test-irc-us"
|
||||||
|
|
||||||
|
========
|
||||||
"endPoint": "106.14.89.110",
|
"endPoint": "106.14.89.110",
|
||||||
"port": "9001",
|
"port": "9001",
|
||||||
"useSSL": false,
|
"useSSL": false,
|
||||||
@@ -29,20 +55,80 @@
|
|||||||
"secretKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
|
"secretKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
|
||||||
"bucketName": "hir-test",
|
"bucketName": "hir-test",
|
||||||
"viewEndpoint": "http://106.14.89.110:9001/hir-test/"
|
"viewEndpoint": "http://106.14.89.110:9001/hir-test/"
|
||||||
}
|
>>>>>>>> Test_IRC_Net8:IRC.Core.SCP/appsettings.Test_IRC_SCP.json
|
||||||
|
},
|
||||||
|
|
||||||
|
"AWS": {
|
||||||
|
"endPoint": "s3.us-east-1.amazonaws.com",
|
||||||
|
"useSSL": false,
|
||||||
|
"accessKey": "AKIAZQ3DRSOHFPJJ6FEU",
|
||||||
|
"secretKey": "l+yjtvV7Z4jiwm/7xCYv30UeUj/SvuqqYzAwjJHf",
|
||||||
|
"bucketName": "ei-irc-test-store",
|
||||||
|
"viewEndpoint": "https://ei-irc-test-store.s3.amazonaws.com/"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"RemoteNew": "Server=106.14.89.110,1435;Database=Test_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
"RemoteNew": "Server=106.14.89.110,1435;Database=Test_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
"Hangfire": "Server=106.14.89.110,1435;Database=Test_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
"Hangfire": "Server=106.14.89.110,1435;Database=Test_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||||
},
|
},
|
||||||
|
"BasicSystemConfig": {
|
||||||
|
|
||||||
|
"OpenUserComplexPassword": false,
|
||||||
|
|
||||||
|
"OpenSignDocumentBeforeWork": false,
|
||||||
|
|
||||||
|
"OpenTrialRelationDelete": true,
|
||||||
|
|
||||||
|
"OpenLoginLimit": false,
|
||||||
|
"LoginMaxFailCount": 5,
|
||||||
|
|
||||||
|
<<<<<<<< HEAD:IRaCIS.Core.API/appsettings.US_Test_IRC.json
|
||||||
|
"LoginFailLockMinutes": 30,
|
||||||
|
"AutoLoginOutMinutes": 60,
|
||||||
|
|
||||||
|
"ContinuousReadingTimeMin": 120,
|
||||||
|
|
||||||
|
"ReadingRestTimeMin": 10
|
||||||
|
},
|
||||||
|
|
||||||
|
"SystemEmailSendConfig": {
|
||||||
|
"Port": 587,
|
||||||
|
"Host": "smtp-mail.outlook.com",
|
||||||
|
"FromEmail": "donotreply@elevateimaging.ai",
|
||||||
|
"FromName": "LiLi",
|
||||||
|
"AuthorizationCode": "Q#669869497420ul",
|
||||||
|
|
||||||
|
"OrganizationName": "Elevate Imaging",
|
||||||
|
"OrganizationNameCN": "Elevate Imaging",
|
||||||
|
"CompanyName": "Elevate Imaging Inc.",
|
||||||
|
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||||
|
"CompanyShortName": "Elevate Imaging",
|
||||||
|
"CompanyShortNameCN": "展影医疗",
|
||||||
|
"SiteUrl": "https://lili.test.elevateimaging.ai/login"
|
||||||
|
}
|
||||||
|
========
|
||||||
|
"LoginFailLockMinutes": 30
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
"SystemEmailSendConfig": {
|
||||||
|
"Port": 465,
|
||||||
|
"Host": "smtp.qiye.aliyun.com",
|
||||||
|
"FromEmail": "test-study@extimaging.com",
|
||||||
|
"FromName": "Test_Study",
|
||||||
|
"AuthorizationCode": "zhanying123",
|
||||||
|
>>>>>>>> Test_IRC_Net8:IRC.Core.SCP/appsettings.Test_IRC_SCP.json
|
||||||
|
|
||||||
|
"SiteUrl": "http://study.test.extimaging.com/login"
|
||||||
|
},
|
||||||
"DicomSCPServiceConfig": {
|
"DicomSCPServiceConfig": {
|
||||||
"CalledAEList": [
|
"CalledAEList": [
|
||||||
"STORESCP"
|
"STORESCP",
|
||||||
|
"Value1",
|
||||||
|
"Value2",
|
||||||
|
"Value3"
|
||||||
],
|
],
|
||||||
"ServerPort": 11112
|
"ServerPort": 11112
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ObjectStoreService": {
|
|
||||||
"ObjectStoreUse": "AWS",
|
|
||||||
"AWS": {
|
|
||||||
"Region": "us-east-1",
|
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
|
||||||
"UseSSL": true,
|
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/lili_s3_access",
|
|
||||||
"AccessKeyId": "AKIAW3MEAFJXZ2TZK7GM",
|
|
||||||
"SecretAccessKey": "9MLQCQ1HifEVW1gf068zBRAOb4wNnfrOkvBVByth",
|
|
||||||
"BucketName": "ei-med-s3-lili-store",
|
|
||||||
"ViewEndpoint": "https://ei-med-s3-lili-store.s3.amazonaws.com",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"RemoteNew": "Server=us-prod-mssql-service,1433;Database=US_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
|
||||||
"Hangfire": "Server=us-prod-mssql-service,1433;Database=US_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
|
||||||
},
|
|
||||||
"DicomSCPServiceConfig": {
|
|
||||||
"CalledAEList": [
|
|
||||||
"STORESCP"
|
|
||||||
],
|
|
||||||
"ServerPort": 11112
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ObjectStoreService": {
|
|
||||||
"ObjectStoreUse": "AWS",
|
|
||||||
"AWS": {
|
|
||||||
"Region": "us-east-1",
|
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
|
||||||
"UseSSL": true,
|
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/uat_s3_access",
|
|
||||||
"AccessKeyId": "AKIAW3MEAFJX7IPXISP4",
|
|
||||||
"SecretAccessKey": "Pgrg3le5jPxZQ7MR1yYNS30J0XRyJeKVyIIjElXc",
|
|
||||||
"BucketName": "ei-med-s3-lili-uat-store",
|
|
||||||
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com/",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"RemoteNew": "Server=us-mssql-service,1433;Database=US_Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
|
||||||
"Hangfire": "Server=us-mssql-service,1433;Database=US_Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
|
||||||
},
|
|
||||||
"DicomSCPServiceConfig": {
|
|
||||||
"CalledAEList": [
|
|
||||||
"STORESCP"
|
|
||||||
],
|
|
||||||
"ServerPort": 11112
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -7,29 +7,61 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ObjectStoreService": {
|
"ObjectStoreService": {
|
||||||
"ObjectStoreUse": "AliyunOSS",
|
"ObjectStoreUse": "MinIO",
|
||||||
"AliyunOSS": {
|
"AliyunOSS": {
|
||||||
"RegionId": "cn-shanghai",
|
"regionId": "cn-shanghai",
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
"internalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
"endpoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||||
"AccessKeyId": "LTAI5tRRZehUp2V9pyTPtAJm",
|
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
|
||||||
"AccessKeySecret": "FLizxkHsMm4CGYHtkV8E3PNJJZU7oV",
|
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
|
||||||
"RoleArn": "acs:ram::1899121822495495:role/dev-oss-access",
|
"bucketName": "zy-irc-uat-store",
|
||||||
"BucketName": "zy-irc-uat-store",
|
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
|
||||||
"ViewEndpoint": "https://zy-irc-uat-store.oss-cn-shanghai.aliyuncs.com",
|
"viewEndpoint": "https://zy-irc-uat-store.oss-cn-shanghai.aliyuncs.com",
|
||||||
"Region": "oss-cn-shanghai",
|
"region": "oss-cn-shanghai"
|
||||||
"DurationSeconds": 7200
|
},
|
||||||
|
|
||||||
|
"AWS": {
|
||||||
|
"endPoint": "s3.us-east-1.amazonaws.com",
|
||||||
|
"useSSL": false,
|
||||||
|
"accessKey": "AKIAZQ3DRSOHFPJJ6FEU",
|
||||||
|
"secretKey": "l+yjtvV7Z4jiwm/7xCYv30UeUj/SvuqqYzAwjJHf",
|
||||||
|
"bucketName": "ei-irc-test-store",
|
||||||
|
"viewEndpoint": "https://ei-irc-test-store.s3.amazonaws.com/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"RemoteNew": "Server=47.117.164.182,1434;Database=Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
"RemoteNew": "Server=47.117.164.182,1434;Database=Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
"Hangfire": "Server=47.117.164.182,1434;Database=Uat_IRC.Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
"Hangfire": "Server=47.117.164.182,1434;Database=Uat_IRC.Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||||
},
|
},
|
||||||
|
"BasicSystemConfig": {
|
||||||
|
|
||||||
|
"OpenUserComplexPassword": false,
|
||||||
|
|
||||||
|
"OpenSignDocumentBeforeWork": false,
|
||||||
|
|
||||||
|
"OpenTrialRelationDelete": true,
|
||||||
|
|
||||||
|
"OpenLoginLimit": false,
|
||||||
|
"LoginMaxFailCount": 5,
|
||||||
|
|
||||||
|
"LoginFailLockMinutes": 30
|
||||||
|
},
|
||||||
|
|
||||||
|
"SystemEmailSendConfig": {
|
||||||
|
"Port": 465,
|
||||||
|
"Host": "smtp.qiye.aliyun.com",
|
||||||
|
"FromEmail": "uat-study@extimaging.com",
|
||||||
|
"FromName": "Uat_Study",
|
||||||
|
"AuthorizationCode": "zhanying123",
|
||||||
|
"SiteUrl": "http://study.uat.extimaging.com/login"
|
||||||
|
},
|
||||||
"DicomSCPServiceConfig": {
|
"DicomSCPServiceConfig": {
|
||||||
"CalledAEList": [
|
"CalledAEList": [
|
||||||
"STORESCP"
|
"STORESCP",
|
||||||
|
"Value1",
|
||||||
|
"Value2",
|
||||||
|
"Value3"
|
||||||
],
|
],
|
||||||
"ServerPort": 11112
|
"ServerPort": 11112
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infra.EFCore",
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infrastructure", "IRaCIS.Core.Infrastructure\IRaCIS.Core.Infrastructure.csproj", "{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infrastructure", "IRaCIS.Core.Infrastructure\IRaCIS.Core.Infrastructure.csproj", "{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRC.Core.SCP", "IRC.Core.SCP\IRC.Core.SCP.csproj", "{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IRC.Core.SCP", "IRC.Core.SCP\IRC.Core.SCP.csproj", "{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace EFSaving.Concurrency
|
||||||
|
{
|
||||||
|
public class Sample
|
||||||
|
{
|
||||||
|
public static void Run()
|
||||||
|
{
|
||||||
|
// Ensure database is created and has a person in it
|
||||||
|
using (var setupContext = new PersonContext())
|
||||||
|
{
|
||||||
|
setupContext.Database.EnsureDeleted();
|
||||||
|
setupContext.Database.EnsureCreated();
|
||||||
|
|
||||||
|
setupContext.People.Add(new Person { FirstName = "John", LastName = "Doe" });
|
||||||
|
setupContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region ConcurrencyHandlingCode
|
||||||
|
using var context = new PersonContext();
|
||||||
|
// Fetch a person from database and change phone number
|
||||||
|
var person = context.People.Single(p => p.PersonId == 1);
|
||||||
|
person.PhoneNumber = "555-555-5555";
|
||||||
|
|
||||||
|
// Change the person's name in the database to simulate a concurrency conflict
|
||||||
|
context.Database.ExecuteSqlRaw(
|
||||||
|
"UPDATE dbo.People SET FirstName = 'Jane' WHERE PersonId = 1");
|
||||||
|
|
||||||
|
var saved = false;
|
||||||
|
while (!saved)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Attempt to save changes to the database
|
||||||
|
context.SaveChanges();
|
||||||
|
saved = true;
|
||||||
|
}
|
||||||
|
catch (DbUpdateConcurrencyException ex)
|
||||||
|
{
|
||||||
|
foreach (var entry in ex.Entries)
|
||||||
|
{
|
||||||
|
if (entry.Entity is Person)
|
||||||
|
{
|
||||||
|
var proposedValues = entry.CurrentValues;
|
||||||
|
var databaseValues = entry.GetDatabaseValues();
|
||||||
|
|
||||||
|
foreach (var property in proposedValues.Properties)
|
||||||
|
{
|
||||||
|
var proposedValue = proposedValues[property];
|
||||||
|
var databaseValue = databaseValues[property];
|
||||||
|
|
||||||
|
// TODO: decide which value should be written to database
|
||||||
|
// proposedValues[property] = <value to be saved>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh original values to bypass next concurrency check
|
||||||
|
entry.OriginalValues.SetValues(databaseValues);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotSupportedException(
|
||||||
|
"Don't know how to handle concurrency conflicts for "
|
||||||
|
+ entry.Metadata.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PersonContext : DbContext
|
||||||
|
{
|
||||||
|
public DbSet<Person> People { get; set; }
|
||||||
|
|
||||||
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
|
{
|
||||||
|
// Requires NuGet package Microsoft.EntityFrameworkCore.SqlServer
|
||||||
|
optionsBuilder.UseSqlServer(
|
||||||
|
@"Server=(localdb)\mssqllocaldb;Database=EFSaving.Concurrency;Trusted_Connection=True");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Person
|
||||||
|
{
|
||||||
|
public int PersonId { get; set; }
|
||||||
|
|
||||||
|
[ConcurrencyCheck]
|
||||||
|
public string FirstName { get; set; }
|
||||||
|
|
||||||
|
[ConcurrencyCheck]
|
||||||
|
public string LastName { get; set; }
|
||||||
|
|
||||||
|
public string PhoneNumber { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using EasyCaching.Core;
|
||||||
using IRaCIS.Application.Interfaces;
|
using IRaCIS.Application.Interfaces;
|
||||||
using IRaCIS.Application.Contracts;
|
using IRaCIS.Application.Contracts;
|
||||||
using IRaCIS.Core.Application.Auth;
|
using IRaCIS.Core.Application.Auth;
|
||||||
@@ -14,7 +15,7 @@ using System.Text;
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using IRaCIS.Core.Application.Interfaces;
|
using IRaCIS.Core.Application.Interfaces;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using IRaCIS.Core.Application.Service;
|
using IRaCIS.Application.Services;
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
using IRaCIS.Core.Domain.Models;
|
using IRaCIS.Core.Domain.Models;
|
||||||
using IRaCIS.Core.Infrastructure;
|
using IRaCIS.Core.Infrastructure;
|
||||||
@@ -22,6 +23,9 @@ using System.Linq;
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Aliyun.Acs.Core.Profile;
|
||||||
|
using Aliyun.Acs.Core.Auth.Sts;
|
||||||
|
using Aliyun.Acs.Core;
|
||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Core.Application.Helper;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using IRaCIS.Core.Application.Contracts;
|
using IRaCIS.Core.Application.Contracts;
|
||||||
@@ -29,15 +33,6 @@ using LoginReturnDTO = IRaCIS.Application.Contracts.LoginReturnDTO;
|
|||||||
using DocumentFormat.OpenXml.Spreadsheet;
|
using DocumentFormat.OpenXml.Spreadsheet;
|
||||||
using AutoMapper.QueryableExtensions;
|
using AutoMapper.QueryableExtensions;
|
||||||
using NetTopologySuite.Algorithm;
|
using NetTopologySuite.Algorithm;
|
||||||
using ZiggyCreatures.Caching.Fusion;
|
|
||||||
using AlibabaCloud.SDK.Sts20150401;
|
|
||||||
using AlibabaCloud.SDK.Sts20150401.Models;
|
|
||||||
using Org.BouncyCastle.Tls;
|
|
||||||
using Amazon.SecurityToken.Model;
|
|
||||||
using Amazon.SecurityToken;
|
|
||||||
using Amazon;
|
|
||||||
using AssumeRoleRequest = Amazon.SecurityToken.Model.AssumeRoleRequest;
|
|
||||||
using AutoMapper;
|
|
||||||
|
|
||||||
namespace IRaCIS.Api.Controllers
|
namespace IRaCIS.Api.Controllers
|
||||||
{
|
{
|
||||||
@@ -105,17 +100,13 @@ namespace IRaCIS.Api.Controllers
|
|||||||
[HttpPost, Route("user/login")]
|
[HttpPost, Route("user/login")]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
public async Task<IResponseOutput> Login(UserLoginDTO loginUser,
|
public async Task<IResponseOutput> Login(UserLoginDTO loginUser,
|
||||||
[FromServices] IFusionCache _fusionCache,
|
[FromServices] IEasyCachingProvider provider,
|
||||||
[FromServices] IUserService _userService,
|
[FromServices] IUserService _userService,
|
||||||
[FromServices] ITokenService _tokenService,
|
[FromServices] ITokenService _tokenService,
|
||||||
[FromServices] IReadingImageTaskService readingImageTaskService,
|
[FromServices] IReadingImageTaskService readingImageTaskService,
|
||||||
[FromServices] IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig,
|
IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig,
|
||||||
[FromServices] IOptionsMonitor<SystemEmailSendConfig> _emailConfig,
|
IMailVerificationService _mailVerificationService)
|
||||||
|
|
||||||
[FromServices] IMailVerificationService _mailVerificationService)
|
|
||||||
{
|
{
|
||||||
var emailConfig = _emailConfig.CurrentValue;
|
|
||||||
var companyInfo = new SystemEmailSendConfigView() { CompanyName = emailConfig.CompanyName, CompanyNameCN = emailConfig.CompanyNameCN, CompanyShortName = emailConfig.CompanyShortName, CompanyShortNameCN = emailConfig.CompanyShortNameCN };
|
|
||||||
|
|
||||||
//MFA 邮箱验证 前端传递用户Id 和MFACode
|
//MFA 邮箱验证 前端传递用户Id 和MFACode
|
||||||
if (loginUser.UserId != null && _verifyConfig.CurrentValue.OpenLoginMFA)
|
if (loginUser.UserId != null && _verifyConfig.CurrentValue.OpenLoginMFA)
|
||||||
@@ -148,11 +139,10 @@ namespace IRaCIS.Api.Controllers
|
|||||||
// 验证阅片休息时间
|
// 验证阅片休息时间
|
||||||
await readingImageTaskService.ResetReadingRestTime(userId);
|
await readingImageTaskService.ResetReadingRestTime(userId);
|
||||||
|
|
||||||
await _fusionCache.SetAsync(CacheKeys.UserToken(userId), loginReturn.JWTStr, TimeSpan.FromDays(7));
|
await provider.SetAsync(userId.ToString(), loginReturn.JWTStr, TimeSpan.FromDays(7));
|
||||||
|
|
||||||
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(userId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(_verifyConfig.CurrentValue.AutoLoginOutMinutes));
|
await provider.SetAsync($"{userId.ToString()}_Online", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(_verifyConfig.CurrentValue.AutoLoginOutMinutes));
|
||||||
|
|
||||||
loginReturn.CompanyInfo = companyInfo;
|
|
||||||
return ResponseOutput.Ok(loginReturn);
|
return ResponseOutput.Ok(loginReturn);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -227,9 +217,9 @@ namespace IRaCIS.Api.Controllers
|
|||||||
|
|
||||||
if (_verifyConfig.CurrentValue.OpenLoginMFA)
|
if (_verifyConfig.CurrentValue.OpenLoginMFA)
|
||||||
{
|
{
|
||||||
|
//发版屏蔽
|
||||||
|
|
||||||
|
//returnModel.Data.JWTStr = _tokenService.GetToken(IRaCISClaims.Create(returnModel.Data.BasicInfo));
|
||||||
|
|
||||||
|
|
||||||
//MFA 发送邮件
|
//MFA 发送邮件
|
||||||
|
|
||||||
@@ -237,23 +227,13 @@ namespace IRaCIS.Api.Controllers
|
|||||||
|
|
||||||
var email = returnModel.Data.BasicInfo.EMail;
|
var email = returnModel.Data.BasicInfo.EMail;
|
||||||
|
|
||||||
var hiddenEmail = IRCEmailPasswordHelper.MaskEmail(email);
|
var hiddenEmail = EmailMaskHelper.MaskEmail(email);
|
||||||
|
|
||||||
returnModel.Data.BasicInfo.EMail = hiddenEmail;
|
returnModel.Data.BasicInfo.EMail = hiddenEmail;
|
||||||
|
|
||||||
//修改密码
|
|
||||||
if (returnModel.Data.BasicInfo.IsFirstAdd || returnModel.Data.BasicInfo.LoginState == 1)
|
|
||||||
{
|
|
||||||
returnModel.Data.JWTStr = _tokenService.GetToken(IRaCISClaims.Create(returnModel.Data.BasicInfo));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//正常登录才发送邮件
|
|
||||||
await _userService.SendMFAEmail(userId);
|
await _userService.SendMFAEmail(userId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
returnModel.Data.JWTStr = _tokenService.GetToken(IRaCISClaims.Create(returnModel.Data.BasicInfo));
|
returnModel.Data.JWTStr = _tokenService.GetToken(IRaCISClaims.Create(returnModel.Data.BasicInfo));
|
||||||
@@ -274,14 +254,12 @@ namespace IRaCIS.Api.Controllers
|
|||||||
// 验证阅片休息时间
|
// 验证阅片休息时间
|
||||||
await readingImageTaskService.ResetReadingRestTime(returnModel.Data.BasicInfo.Id);
|
await readingImageTaskService.ResetReadingRestTime(returnModel.Data.BasicInfo.Id);
|
||||||
|
|
||||||
await _fusionCache.SetAsync(CacheKeys.UserToken(userId), returnModel.Data.JWTStr, TimeSpan.FromDays(7));
|
await provider.SetAsync(userId.ToString(), returnModel.Data.JWTStr, TimeSpan.FromDays(7));
|
||||||
|
|
||||||
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(userId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(_verifyConfig.CurrentValue.AutoLoginOutMinutes));
|
await provider.SetAsync($"{userId.ToString()}_Online", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(_verifyConfig.CurrentValue.AutoLoginOutMinutes));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
returnModel.Data.CompanyInfo = companyInfo;
|
|
||||||
return returnModel;
|
return returnModel;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -291,14 +269,8 @@ namespace IRaCIS.Api.Controllers
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[AllowAnonymous]
|
|
||||||
[HttpGet, Route("user/getPublicKey")]
|
|
||||||
public IResponseOutput GetPublicKey([FromServices] IOptionsMonitor<IRCEncreptOption> _IRCEncreptOption)
|
|
||||||
{
|
|
||||||
//var pemPublicKey = Encoding.UTF8.GetString(Convert.FromBase64String(_IRCEncreptOption.CurrentValue.Base64RSAPublicKey));
|
|
||||||
|
|
||||||
return ResponseOutput.Ok(_IRCEncreptOption.CurrentValue.Base64RSAPublicKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[HttpGet, Route("imageShare/ShareImage")]
|
[HttpGet, Route("imageShare/ShareImage")]
|
||||||
@@ -321,98 +293,105 @@ namespace IRaCIS.Api.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("user/GetObjectStoreToken")]
|
[HttpGet("user/GetObjectStoreToken")]
|
||||||
public async Task<IResponseOutput> GetObjectStoreTokenAsync([FromServices] IOptionsMonitor<ObjectStoreServiceOptions> options, [FromServices] IOSSService _oSSService)
|
public IResponseOutput GetObjectStoreToken([FromServices] IOptionsMonitor<ObjectStoreServiceOptions> options)
|
||||||
|
{
|
||||||
|
var serviceOption = options.CurrentValue;
|
||||||
|
|
||||||
|
if (Enum.TryParse<ObjectStoreUse>(serviceOption.ObjectStoreUse, out var parsedEnum) && parsedEnum == ObjectStoreUse.AliyunOSS)
|
||||||
{
|
{
|
||||||
|
|
||||||
var result = _oSSService.GetObjectStoreTempToken();
|
var ossOptions = serviceOption.AliyunOSS;
|
||||||
|
|
||||||
//result.AWS = await GetAWSTemToken(options.CurrentValue);
|
return ResponseOutput.Ok(new ObjectStoreDTO() { ObjectStoreUse = serviceOption.ObjectStoreUse, MinIO = serviceOption.MinIO, AliyunOSS = serviceOption.AliyunOSS, AWS = serviceOption.AWS });
|
||||||
|
|
||||||
return ResponseOutput.Ok(result);
|
#region 临时token 屏蔽
|
||||||
|
//IClientProfile profile = DefaultProfile.GetProfile(ossOptions.RegionId, ossOptions.AccessKeyId, ossOptions.AccessKeySecret);
|
||||||
}
|
//DefaultAcsClient client = new DefaultAcsClient(profile);
|
||||||
|
|
||||||
|
|
||||||
private async Task<AWSTempToken> GetAWSTemToken(ObjectStoreServiceOptions serviceOption)
|
//// 创建一个STS请求
|
||||||
{
|
//AssumeRoleRequest request = new AssumeRoleRequest
|
||||||
var awsOptions = serviceOption.AWS;
|
|
||||||
|
|
||||||
//aws 临时凭证
|
|
||||||
// 创建 STS 客户端
|
|
||||||
var stsClient = new AmazonSecurityTokenServiceClient(awsOptions.AccessKeyId, awsOptions.SecretAccessKey);
|
|
||||||
|
|
||||||
// 使用 AssumeRole 请求临时凭证
|
|
||||||
var assumeRoleRequest = new AssumeRoleRequest
|
|
||||||
{
|
|
||||||
|
|
||||||
RoleArn = awsOptions.RoleArn, // 角色 ARN
|
|
||||||
RoleSessionName = $"session-name-{NewId.NextGuid()}",
|
|
||||||
DurationSeconds = awsOptions.DurationSeconds // 临时凭证有效期
|
|
||||||
};
|
|
||||||
|
|
||||||
var assumeRoleResponse = await stsClient.AssumeRoleAsync(assumeRoleRequest);
|
|
||||||
|
|
||||||
var credentials = assumeRoleResponse.Credentials;
|
|
||||||
|
|
||||||
var tempToken = new AWSTempToken()
|
|
||||||
{
|
|
||||||
AccessKeyId = credentials.AccessKeyId,
|
|
||||||
SecretAccessKey = credentials.SecretAccessKey,
|
|
||||||
SessionToken = credentials.SessionToken,
|
|
||||||
Expiration = credentials.Expiration,
|
|
||||||
Region = awsOptions.Region,
|
|
||||||
BucketName = awsOptions.BucketName,
|
|
||||||
EndPoint = awsOptions.EndPoint,
|
|
||||||
ViewEndpoint = awsOptions.ViewEndpoint,
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
return tempToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#region aliyun-net-sdk-sts 之前
|
|
||||||
//[HttpGet("user/GenerateSTS")]
|
|
||||||
//public IResponseOutput GenerateSTS([FromServices] IOptionsMonitor<AliyunOSSOptions> options)
|
|
||||||
//{
|
//{
|
||||||
// var ossOptions = options.CurrentValue;
|
// RoleArn = ossOptions.RoleArn, // 角色ARN,需要替换为你的角色ARN
|
||||||
|
|
||||||
|
|
||||||
// IClientProfile profile = DefaultProfile.GetProfile(ossOptions.regionId, ossOptions.accessKeyId, ossOptions.accessKeySecret);
|
|
||||||
// DefaultAcsClient client = new DefaultAcsClient(profile);
|
|
||||||
|
|
||||||
|
|
||||||
// // 创建一个STS请求
|
|
||||||
// AssumeRoleRequest request = new AssumeRoleRequest
|
|
||||||
// {
|
|
||||||
// RoleArn = ossOptions.roleArn, // 角色ARN,需要替换为你的角色ARN
|
|
||||||
// RoleSessionName = $"session-name-{NewId.NextGuid()}", // 角色会话名称,可自定义
|
// RoleSessionName = $"session-name-{NewId.NextGuid()}", // 角色会话名称,可自定义
|
||||||
// DurationSeconds = 900, // 令牌有效期(单位:秒),这里设置为1小时
|
// DurationSeconds = 900, // 令牌有效期(单位:秒),这里设置为1小时
|
||||||
// };
|
//};
|
||||||
|
|
||||||
|
|
||||||
// AssumeRoleResponse response = client.GetAcsResponse(request);
|
//AssumeRoleResponse response = client.GetAcsResponse(request);
|
||||||
|
|
||||||
// // 返回STS令牌信息给前端
|
//// 返回STS令牌信息给前端
|
||||||
// var stsToken = new
|
//var stsToken = new ObjectStoreDTO()
|
||||||
|
//{
|
||||||
|
// ObjectStoreUse = serviceOption.ObjectStoreUse,
|
||||||
|
// AliyunOSS = new AliyunOSSTempToken()
|
||||||
// {
|
// {
|
||||||
// AccessKeyId = response.Credentials.AccessKeyId,
|
// AccessKeyId = response.Credentials.AccessKeyId,
|
||||||
// AccessKeySecret = response.Credentials.AccessKeySecret,
|
// AccessKeySecret = response.Credentials.AccessKeySecret,
|
||||||
// SecurityToken = response.Credentials.SecurityToken,
|
// SecurityToken = response.Credentials.SecurityToken,
|
||||||
// Expiration = response.Credentials.Expiration,
|
// Expiration = response.Credentials.Expiration,
|
||||||
|
|
||||||
// Region = ossOptions.region,
|
// Region = ossOptions.Region,
|
||||||
// BucketName = ossOptions.bucketName,
|
// BucketName = ossOptions.BucketName,
|
||||||
// ViewEndpoint = ossOptions.viewEndpoint,
|
// ViewEndpoint = ossOptions.ViewEndpoint,
|
||||||
|
|
||||||
// };
|
// },
|
||||||
|
// MinIO = serviceOption.MinIO
|
||||||
|
//};
|
||||||
|
//return ResponseOutput.Ok(stsToken);
|
||||||
|
|
||||||
// return ResponseOutput.Ok(stsToken);
|
|
||||||
|
|
||||||
//}
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (Enum.TryParse<ObjectStoreUse>(serviceOption.ObjectStoreUse, out var parsedValue) && parsedValue == ObjectStoreUse.MinIO)
|
||||||
|
{
|
||||||
|
return ResponseOutput.Ok(new ObjectStoreDTO() { ObjectStoreUse = serviceOption.ObjectStoreUse, MinIO = serviceOption.MinIO, AWS = serviceOption.AWS });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ResponseOutput.Ok(new ObjectStoreDTO() { ObjectStoreUse = serviceOption.ObjectStoreUse, MinIO = serviceOption.MinIO, AWS = serviceOption.AWS });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("user/GenerateSTS")]
|
||||||
|
public IResponseOutput GenerateSTS([FromServices] IOptionsMonitor<AliyunOSSOptions> options)
|
||||||
|
{
|
||||||
|
var ossOptions = options.CurrentValue;
|
||||||
|
|
||||||
|
|
||||||
|
IClientProfile profile = DefaultProfile.GetProfile(ossOptions.regionId, ossOptions.accessKeyId, ossOptions.accessKeySecret);
|
||||||
|
DefaultAcsClient client = new DefaultAcsClient(profile);
|
||||||
|
|
||||||
|
|
||||||
|
// 创建一个STS请求
|
||||||
|
AssumeRoleRequest request = new AssumeRoleRequest
|
||||||
|
{
|
||||||
|
RoleArn = ossOptions.roleArn, // 角色ARN,需要替换为你的角色ARN
|
||||||
|
RoleSessionName = $"session-name-{NewId.NextGuid()}", // 角色会话名称,可自定义
|
||||||
|
DurationSeconds = 900, // 令牌有效期(单位:秒),这里设置为1小时
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
AssumeRoleResponse response = client.GetAcsResponse(request);
|
||||||
|
|
||||||
|
// 返回STS令牌信息给前端
|
||||||
|
var stsToken = new
|
||||||
|
{
|
||||||
|
AccessKeyId = response.Credentials.AccessKeyId,
|
||||||
|
AccessKeySecret = response.Credentials.AccessKeySecret,
|
||||||
|
SecurityToken = response.Credentials.SecurityToken,
|
||||||
|
Expiration = response.Credentials.Expiration,
|
||||||
|
|
||||||
|
Region = ossOptions.region,
|
||||||
|
BucketName = ossOptions.bucketName,
|
||||||
|
ViewEndpoint = ossOptions.viewEndpoint,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return ResponseOutput.Ok(stsToken);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -448,7 +427,7 @@ namespace IRaCIS.Api.Controllers
|
|||||||
|
|
||||||
[HttpGet, Route("ip")]
|
[HttpGet, Route("ip")]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
public IResponseOutput Get([FromServices] IHttpContextAccessor _context)
|
public IResponseOutput Get([FromServices] IHttpContextAccessor _context/*, [FromServices] IUserService _userService*/)
|
||||||
{
|
{
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
@@ -469,7 +448,7 @@ namespace IRaCIS.Api.Controllers
|
|||||||
|
|
||||||
[HttpGet, Route("ip2")]
|
[HttpGet, Route("ip2")]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
public IResponseOutput Get2([FromServices] IHttpContextAccessor _context)
|
public IResponseOutput Get2([FromServices] IHttpContextAccessor _context, [FromServices] IRepository _userService)
|
||||||
{
|
{
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using IRaCIS.Core.Application.Filter;
|
|||||||
using IRaCIS.Core.Infrastructure.Extention;
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using IRaCIS.Core.Application.Service;
|
using IRaCIS.Application.Services;
|
||||||
using IRaCIS.Core.Application.Service.Inspection.DTO;
|
using IRaCIS.Core.Application.Service.Inspection.DTO;
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
using IRaCIS.Core.Domain.Models;
|
using IRaCIS.Core.Domain.Models;
|
||||||
@@ -19,12 +19,18 @@ namespace IRaCIS.Core.API.Controllers.Special
|
|||||||
//谨慎修改 涉及到财务模块
|
//谨慎修改 涉及到财务模块
|
||||||
|
|
||||||
[ApiController, Authorize, ApiExplorerSettings(GroupName = "Financial")]
|
[ApiController, Authorize, ApiExplorerSettings(GroupName = "Financial")]
|
||||||
public class FinancialChangeController(
|
public class FinancialChangeController : ControllerBase
|
||||||
ITrialService _trialService,
|
|
||||||
ICalculateService _calculateService,
|
|
||||||
IStringLocalizer _localizer) : ControllerBase
|
|
||||||
{
|
{
|
||||||
|
private readonly ITrialService _trialService;
|
||||||
|
private readonly ICalculateService _calculateService;
|
||||||
|
private IStringLocalizer _localizer { get; set; }
|
||||||
|
public FinancialChangeController(ITrialService trialService, ICalculateService calculateService, IStringLocalizer localizer
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_localizer = localizer;
|
||||||
|
_trialService = trialService;
|
||||||
|
_calculateService = calculateService;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//[TrialAudit(AuditType.TrialAudit, AuditOptType.AddOrUpdateTrial)]
|
//[TrialAudit(AuditType.TrialAudit, AuditOptType.AddOrUpdateTrial)]
|
||||||
|
|||||||
@@ -26,18 +26,77 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
|
|
||||||
[ApiController, ApiExplorerSettings(GroupName = "Reviewer")]
|
[ApiController, ApiExplorerSettings(GroupName = "Reviewer")]
|
||||||
[UnitOfWork]
|
[UnitOfWork]
|
||||||
public class InspectionController(
|
public class InspectionController : ControllerBase
|
||||||
ITrialDocumentService _trialDocumentService,
|
|
||||||
IReadingImageTaskService _iReadingImageTaskService,
|
|
||||||
ITrialConfigService _trialConfigService,
|
|
||||||
IClinicalAnswerService _clinicalAnswerService,
|
|
||||||
IReadingClinicalDataService _readingClinicalDataService,
|
|
||||||
IQCOperationService _qCOperationService,
|
|
||||||
IInspectionService _inspectionService,
|
|
||||||
IReadingMedicalReviewService _readingMedicalReviewService,
|
|
||||||
IReadingMedicineQuestionService _readingMedicineQuestionService
|
|
||||||
) : ControllerBase
|
|
||||||
{
|
{
|
||||||
|
private readonly IRepository _repository;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
private readonly IUserInfo _userInfo;
|
||||||
|
private readonly ITrialDocumentService _trialDocumentService;
|
||||||
|
private readonly IQCListService _qCListService;
|
||||||
|
private readonly IReadingImageTaskService _iReadingImageTaskService;
|
||||||
|
private readonly IHttpContextAccessor _httpContext;
|
||||||
|
private readonly ITrialConfigService _trialConfigService;
|
||||||
|
private readonly INoneDicomStudyService _noneDicomStudyService;
|
||||||
|
private readonly IClinicalAnswerService _clinicalAnswerService;
|
||||||
|
private readonly ISubjectService _subjectService;
|
||||||
|
private readonly IReadingClinicalDataService _readingClinicalDataService;
|
||||||
|
private readonly ISubjectVisitService _subjectVisitService;
|
||||||
|
private readonly IQCOperationService _qCOperationService;
|
||||||
|
private readonly IClinicalDataService _clinicalDataService;
|
||||||
|
private readonly IVisitPlanService _visitPlanService;
|
||||||
|
|
||||||
|
private readonly IInspectionService _inspectionService;
|
||||||
|
private readonly IReadingMedicalReviewService _readingMedicalReviewService;
|
||||||
|
private readonly IReadingMedicineQuestionService _readingMedicineQuestionService;
|
||||||
|
private readonly IRepository<DataInspection> _dataInspectionRepository;
|
||||||
|
private delegate Task<IResponseOutput> executionFun(dynamic data);
|
||||||
|
|
||||||
|
public InspectionController(IRepository repository,
|
||||||
|
IRepository<DataInspection> _repositoryDataInspection,
|
||||||
|
IMapper mapper, IUserInfo userInfo,
|
||||||
|
ITrialDocumentService trialDocumentService,
|
||||||
|
IRepository<DataInspection> dataInspectionRepository,
|
||||||
|
IQCListService _qCListService,
|
||||||
|
IReadingImageTaskService _iReadingImageTaskService,
|
||||||
|
IHttpContextAccessor httpContext,
|
||||||
|
IInspectionService sinspectionService,
|
||||||
|
IReadingMedicalReviewService readingMedicalReviewService,
|
||||||
|
IReadingMedicineQuestionService readingMedicineQuestionService,
|
||||||
|
ITrialConfigService _trialConfigService,
|
||||||
|
INoneDicomStudyService noneDicomStudyService,
|
||||||
|
IClinicalAnswerService clinicalAnswerService,
|
||||||
|
ISubjectService _subjectService,
|
||||||
|
IReadingClinicalDataService _readingClinicalDataService,
|
||||||
|
ISubjectVisitService subjectVisitService,
|
||||||
|
IQCOperationService qCOperationService,
|
||||||
|
IClinicalDataService clinicalDataService,
|
||||||
|
IVisitPlanService visitPlanService
|
||||||
|
)
|
||||||
|
{
|
||||||
|
this._repository = repository;
|
||||||
|
this._mapper = mapper;
|
||||||
|
this._userInfo = userInfo;
|
||||||
|
this._inspectionService = sinspectionService;
|
||||||
|
this._readingMedicalReviewService = readingMedicalReviewService;
|
||||||
|
this._readingMedicineQuestionService = readingMedicineQuestionService;
|
||||||
|
this._trialDocumentService = trialDocumentService;
|
||||||
|
this._qCListService = _qCListService;
|
||||||
|
this._iReadingImageTaskService = _iReadingImageTaskService;
|
||||||
|
this._httpContext = httpContext;
|
||||||
|
this._trialConfigService = _trialConfigService;
|
||||||
|
this._noneDicomStudyService = noneDicomStudyService;
|
||||||
|
this._clinicalAnswerService = clinicalAnswerService;
|
||||||
|
this._subjectService = _subjectService;
|
||||||
|
this._readingClinicalDataService = _readingClinicalDataService;
|
||||||
|
this._subjectVisitService = subjectVisitService;
|
||||||
|
this._qCOperationService = qCOperationService;
|
||||||
|
this._clinicalDataService = clinicalDataService;
|
||||||
|
this._visitPlanService = visitPlanService;
|
||||||
|
this._dataInspectionRepository = dataInspectionRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region 获取稽查数据
|
#region 获取稽查数据
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using DocumentFormat.OpenXml.Drawing;
|
using DocumentFormat.OpenXml.Drawing;
|
||||||
|
using EasyCaching.Core;
|
||||||
using ExcelDataReader;
|
using ExcelDataReader;
|
||||||
using IRaCIS.Application.Contracts;
|
using IRaCIS.Application.Contracts;
|
||||||
using IRaCIS.Application.Interfaces;
|
using IRaCIS.Application.Interfaces;
|
||||||
@@ -9,7 +10,8 @@ using IRaCIS.Core.Application.Contracts.Dicom;
|
|||||||
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
||||||
using IRaCIS.Core.Application.Filter;
|
using IRaCIS.Core.Application.Filter;
|
||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Core.Application.Helper;
|
||||||
using IRaCIS.Core.Application.MassTransit.Command;
|
using IRaCIS.Core.Application.MediatR.CommandAndQueries;
|
||||||
|
using IRaCIS.Core.Application.MediatR.Handlers;
|
||||||
using IRaCIS.Core.Application.Service;
|
using IRaCIS.Core.Application.Service;
|
||||||
using IRaCIS.Core.Application.Service.ImageAndDoc;
|
using IRaCIS.Core.Application.Service.ImageAndDoc;
|
||||||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||||
@@ -19,7 +21,7 @@ using IRaCIS.Core.Infra.EFCore;
|
|||||||
using IRaCIS.Core.Infrastructure;
|
using IRaCIS.Core.Infrastructure;
|
||||||
using IRaCIS.Core.Infrastructure.Extention;
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
using MassTransit.Mediator;
|
using MediatR;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
@@ -38,14 +40,12 @@ using Newtonsoft.Json;
|
|||||||
using SharpCompress.Archives;
|
using SharpCompress.Archives;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ZiggyCreatures.Caching.Fusion;
|
|
||||||
using Path = System.IO.Path;
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
namespace IRaCIS.Core.API.Controllers
|
namespace IRaCIS.Core.API.Controllers
|
||||||
@@ -228,17 +228,69 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
|
|
||||||
[ApiExplorerSettings(GroupName = "Image")]
|
[ApiExplorerSettings(GroupName = "Image")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class StudyController(
|
public class StudyController : UploadBaseController
|
||||||
IMediator _mediator,
|
{
|
||||||
QCCommon _qCCommon,
|
public IMapper _mapper { get; set; }
|
||||||
IUserInfo _userInfo,
|
public IUserInfo _userInfo { get; set; }
|
||||||
IRepository<SubjectVisit> _subjectVisitRepository,
|
private readonly IMediator _mediator;
|
||||||
IStringLocalizer _localizer) : UploadBaseController
|
|
||||||
|
|
||||||
|
public IStringLocalizer _localizer { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
private readonly IWebHostEnvironment _hostEnvironment;
|
||||||
|
|
||||||
|
private readonly IRepository _repository;
|
||||||
|
|
||||||
|
private readonly IEasyCachingProvider _provider;
|
||||||
|
private readonly QCCommon _qCCommon;
|
||||||
|
public StudyController(IMapper mapper, IStringLocalizer localizer, IUserInfo userInfo, IWebHostEnvironment hostEnvironment, IMediator mediator, IEasyCachingProvider provider,
|
||||||
|
QCCommon qCCommon,
|
||||||
|
IRepository repository)
|
||||||
|
{
|
||||||
|
_qCCommon = qCCommon;
|
||||||
|
_provider = provider;
|
||||||
|
_hostEnvironment = hostEnvironment;
|
||||||
|
_mediator = mediator;
|
||||||
|
_localizer = localizer;
|
||||||
|
_mapper = mapper;
|
||||||
|
_userInfo = userInfo;
|
||||||
|
_repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HttpPost, Route("Study/PreArchiveStudy")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
public async Task<IResponseOutput> PreArchiveStudy(PreArchiveStudyCommand preArchiveStudyCommand,
|
||||||
|
[FromServices] IStudyService _studyService,
|
||||||
|
[FromServices] IRepository<StudyMonitor> _studyMonitorRepository)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (_provider.Get<List<SystemAnonymization>>(StaticData.Anonymize.Anonymize_AddFixedFiled).Value == null)
|
||||||
|
{
|
||||||
|
await _mediator.Send(new AnonymizeCacheRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
var savedInfo = _studyService.GetSaveToDicomInfo(preArchiveStudyCommand.SubjectVisitId);
|
||||||
|
|
||||||
|
var studyMonitor = new StudyMonitor()
|
||||||
|
{
|
||||||
|
TrialId = savedInfo.TrialId,
|
||||||
|
SubjectId = savedInfo.SubjectId,
|
||||||
|
SubjectVisitId = savedInfo.SubjectVisitId,
|
||||||
|
|
||||||
|
IsSuccess = false,
|
||||||
|
UploadStartTime = DateTime.Now,
|
||||||
|
IsDicom = preArchiveStudyCommand.IsDicom,
|
||||||
|
IP = _userInfo.IP
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var addEntity = await _studyMonitorRepository.AddAsync(studyMonitor, true);
|
||||||
|
|
||||||
|
return ResponseOutput.Ok(addEntity.Id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>Dicom 归档</summary>
|
/// <summary>Dicom 归档</summary>
|
||||||
@@ -246,8 +298,9 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
[DisableFormValueModelBinding]
|
[DisableFormValueModelBinding]
|
||||||
[DisableRequestSizeLimit]
|
[DisableRequestSizeLimit]
|
||||||
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
public async Task<IResponseOutput> ArchiveStudyNew(Guid trialId, Guid subjectVisitId, string studyInstanceUid, Guid? abandonStudyId, Guid studyMonitorId,
|
public async Task<IResponseOutput> ArchiveStudyNew(/*[FromForm] ArchiveStudyCommand archiveStudyCommand,*/ Guid trialId, Guid subjectVisitId, string studyInstanceUid, Guid? abandonStudyId, Guid studyMonitorId,
|
||||||
[FromServices] ILogger<UploadDownLoadController> _logger,
|
[FromServices] ILogger<UploadDownLoadController> _logger,
|
||||||
|
[FromServices] IEasyCachingProvider _provider,
|
||||||
[FromServices] IStudyService _studyService,
|
[FromServices] IStudyService _studyService,
|
||||||
[FromServices] IHubContext<UploadHub, IUploadClient> _uploadHub,
|
[FromServices] IHubContext<UploadHub, IUploadClient> _uploadHub,
|
||||||
[FromServices] IDicomArchiveService _dicomArchiveService,
|
[FromServices] IDicomArchiveService _dicomArchiveService,
|
||||||
@@ -272,6 +325,22 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
var startTime = DateTime.Now;
|
var startTime = DateTime.Now;
|
||||||
|
|
||||||
|
|
||||||
|
if (_provider.Exists($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}") && _provider.Get<Guid>($"StudyUid_{trialId}_{studyInstanceUid}").Value == _userInfo.Id)
|
||||||
|
{
|
||||||
|
_provider.Set($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}", _userInfo.Id, TimeSpan.FromMinutes(30));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//if (_provider.Exists($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}"))
|
||||||
|
//{
|
||||||
|
// //---当前已有人正在上传和归档该检查!
|
||||||
|
// return ResponseOutput.NotOk(StaticData.International("UploadDownLoad_ArchiveInProgress"));
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// _provider.Set($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}", _userInfo.Id, TimeSpan.FromMinutes(30));
|
||||||
|
//}
|
||||||
|
|
||||||
//到了接口,代表上传结束了
|
//到了接口,代表上传结束了
|
||||||
|
|
||||||
@@ -337,12 +406,13 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
|
_provider.Remove($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}");
|
||||||
|
|
||||||
//---请求异常,请重试!
|
//---请求异常,请重试!
|
||||||
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_RequestError"]);
|
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_RequestError"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
studyMonitor.FileSize = (long)HttpContext.Request.ContentLength;
|
studyMonitor.FileSize = (decimal)HttpContext.Request.ContentLength;
|
||||||
studyMonitor.FileCount = archiveResult.ReceivedFileCount;
|
studyMonitor.FileCount = archiveResult.ReceivedFileCount;
|
||||||
studyMonitor.FailedFileCount = archiveResult.ErrorFiles.Count;
|
studyMonitor.FailedFileCount = archiveResult.ErrorFiles.Count;
|
||||||
studyMonitor.IsDicomReUpload = archiveStudyCommand.AbandonStudyId != null;
|
studyMonitor.IsDicomReUpload = archiveStudyCommand.AbandonStudyId != null;
|
||||||
@@ -375,6 +445,7 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
_provider.Remove($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}");
|
||||||
|
|
||||||
studyMonitor.StudyId = archiveResult.ArchivedDicomStudies.FirstOrDefault()?.Id ?? Guid.Empty;
|
studyMonitor.StudyId = archiveResult.ArchivedDicomStudies.FirstOrDefault()?.Id ?? Guid.Empty;
|
||||||
studyMonitor.StudyCode = archiveResult.ArchivedDicomStudies.FirstOrDefault()?.StudyCode;
|
studyMonitor.StudyCode = archiveResult.ArchivedDicomStudies.FirstOrDefault()?.StudyCode;
|
||||||
@@ -394,26 +465,12 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
|
|
||||||
public class UploadNoneDicomFileCommand
|
public class UploadNoneDicomFileCommand
|
||||||
{
|
{
|
||||||
[NotDefault]
|
public Guid TrialId { get; set; }
|
||||||
public Guid SubjectVisitId { get; set; }
|
public Guid SubjectVisitId { get; set; }
|
||||||
|
public Guid NoneDicomStudyId { get; set; }
|
||||||
|
|
||||||
[NotDefault]
|
|
||||||
public Guid StudyMonitorId { get; set; }
|
public Guid StudyMonitorId { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public Guid? NoneDicomStudyId { get; set; }
|
|
||||||
|
|
||||||
//IR 上传的时候跟任务绑定
|
|
||||||
public Guid? VisitTaskId { get; set; }
|
|
||||||
|
|
||||||
public string RecordPath { get; set; }
|
|
||||||
|
|
||||||
public int FailedFileCount { get; set; }
|
|
||||||
|
|
||||||
public long FileSize { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public List<OSSFileDTO> UploadedFileList { get; set; } = new List<OSSFileDTO>();
|
public List<OSSFileDTO> UploadedFileList { get; set; } = new List<OSSFileDTO>();
|
||||||
|
|
||||||
|
|
||||||
@@ -427,56 +484,18 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 非dicom 上传预上传接口
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="preArchiveStudyCommand"></param>
|
|
||||||
/// <param name="_studyService"></param>
|
|
||||||
/// <param name="_studyMonitorRepository"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost, Route("Study/PreArchiveStudy")]
|
|
||||||
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
|
||||||
public async Task<IResponseOutput> PreArchiveStudy(PreArchiveStudyCommand preArchiveStudyCommand,
|
|
||||||
[FromServices] IStudyService _studyService,
|
|
||||||
[FromServices] IRepository<StudyMonitor> _studyMonitorRepository)
|
|
||||||
{
|
|
||||||
|
|
||||||
var savedInfo = _studyService.GetSaveToDicomInfo(preArchiveStudyCommand.SubjectVisitId);
|
|
||||||
|
|
||||||
var studyMonitor = new StudyMonitor()
|
|
||||||
{
|
|
||||||
TrialId = savedInfo.TrialId,
|
|
||||||
SubjectId = savedInfo.SubjectId,
|
|
||||||
SubjectVisitId = savedInfo.SubjectVisitId,
|
|
||||||
|
|
||||||
IsSuccess = false,
|
|
||||||
UploadStartTime = DateTime.Now,
|
|
||||||
FileCount=preArchiveStudyCommand.FileCount,
|
|
||||||
IsDicom = preArchiveStudyCommand.IsDicom,
|
|
||||||
IP = _userInfo.IP
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
var addEntity = await _studyMonitorRepository.AddAsync(studyMonitor, true);
|
|
||||||
|
|
||||||
return ResponseOutput.Ok(addEntity.Id);
|
|
||||||
|
|
||||||
}
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 上传非Dicom 文件 支持压缩包 多文件上传
|
/// 上传非Dicom 文件 支持压缩包 多文件上传
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="incommand"></param>
|
/// <param name="incommand"></param>
|
||||||
/// <param name="_noneDicomStudyRepository"></param>
|
/// <param name="_noneDicomStudyRepository"></param>
|
||||||
/// <param name="_studyMonitorRepository"></param>
|
/// <param name="_studyMonitorRepository"></param>
|
||||||
/// <param name="_noneDicomStudyFileRepository"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpPost("NoneDicomStudy/UploadNoneDicomFile")]
|
[HttpPost("NoneDicomStudy/UploadNoneDicomFile")]
|
||||||
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
|
||||||
public async Task<IResponseOutput> UploadNoneDicomFile(UploadNoneDicomFileCommand incommand,
|
public async Task<IResponseOutput> UploadNoneDicomFile(UploadNoneDicomFileCommand incommand,
|
||||||
[FromServices] IRepository<NoneDicomStudy> _noneDicomStudyRepository,
|
[FromServices] IRepository<NoneDicomStudy> _noneDicomStudyRepository, [FromServices] IRepository<StudyMonitor> _studyMonitorRepository)
|
||||||
[FromServices] IRepository<StudyMonitor> _studyMonitorRepository,
|
|
||||||
[FromServices] IRepository<NoneDicomStudyFile> _noneDicomStudyFileRepository)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
var subjectVisitId = incommand.SubjectVisitId;
|
var subjectVisitId = incommand.SubjectVisitId;
|
||||||
@@ -484,9 +503,9 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
var noneDicomStudyId = incommand.NoneDicomStudyId;
|
var noneDicomStudyId = incommand.NoneDicomStudyId;
|
||||||
|
|
||||||
|
|
||||||
await _qCCommon.VerifyIsCRCSubmmitAsync(_subjectVisitRepository, _userInfo, subjectVisitId);
|
await _qCCommon.VerifyIsCRCSubmmitAsync(_repository, _userInfo, subjectVisitId);
|
||||||
|
|
||||||
var sv = (await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).Select(t => new { t.TrialId, t.TrialSiteId, t.SubjectId }).FirstOrDefaultAsync()).IfNullThrowConvertException();
|
var sv = (await _repository.Where<SubjectVisit>(t => t.Id == subjectVisitId).Select(t => new { t.TrialId, t.TrialSiteId, t.SubjectId }).FirstOrDefaultAsync()).IfNullThrowConvertException();
|
||||||
|
|
||||||
var studyMonitor = await _studyMonitorRepository.FirstOrDefaultAsync(t => t.Id == studyMonitorId);
|
var studyMonitor = await _studyMonitorRepository.FirstOrDefaultAsync(t => t.Id == studyMonitorId);
|
||||||
|
|
||||||
@@ -494,39 +513,26 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
|
|
||||||
foreach (var item in incommand.UploadedFileList)
|
foreach (var item in incommand.UploadedFileList)
|
||||||
{
|
{
|
||||||
//如果是跟任务绑,那么NoneDicomStudyId 设置为空,不影响之前的检查,同时设置 OriginNoneDicomStudyId 保证关系
|
await _repository.AddAsync(new NoneDicomStudyFile() { FileName = item.FileName, Path = item.FilePath, NoneDicomStudyId = noneDicomStudyId,FileType=item.FileType });
|
||||||
|
|
||||||
if (incommand.VisitTaskId != null && incommand.VisitTaskId != Guid.Empty)
|
|
||||||
{
|
|
||||||
await _noneDicomStudyFileRepository.AddAsync(new NoneDicomStudyFile() { FileName = item.FileName, Path = item.FilePath, OriginNoneDicomStudyId = noneDicomStudyId.Value, VisitTaskId = incommand.VisitTaskId, FileType = item.FileType, FileSize = item.FileFize });
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await _noneDicomStudyFileRepository.AddAsync(new NoneDicomStudyFile() { FileName = item.FileName, Path = item.FilePath, NoneDicomStudyId = noneDicomStudyId.Value, FileType = item.FileType, FileSize = item.FileFize });
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
var uploadFinishedTime = DateTime.Now;
|
var uploadFinishedTime = DateTime.Now;
|
||||||
|
|
||||||
var noneDicomStudy = await _noneDicomStudyRepository.FirstOrDefaultAsync((t => t.Id == noneDicomStudyId));
|
var noneDicomStudy = await _noneDicomStudyRepository.FirstOrDefaultAsync((t => t.Id == noneDicomStudyId));
|
||||||
|
|
||||||
noneDicomStudy.FileCount = noneDicomStudy.FileCount + (incommand.VisitTaskId != null ? 0 : incommand.UploadedFileList.Count);
|
noneDicomStudy.FileCount = noneDicomStudy.FileCount + incommand.UploadedFileList.Count;
|
||||||
|
|
||||||
studyMonitor.RecordPath = incommand.RecordPath;
|
studyMonitor.FileCount = incommand.UploadedFileList.Count;
|
||||||
studyMonitor.FailedFileCount = incommand.FailedFileCount;
|
|
||||||
studyMonitor.IsSuccess = incommand.FailedFileCount == 0;
|
|
||||||
studyMonitor.FileSize = incommand.UploadedFileList.Sum(t => t.FileFize);
|
studyMonitor.FileSize = incommand.UploadedFileList.Sum(t => t.FileFize);
|
||||||
studyMonitor.IsDicom = false;
|
studyMonitor.IsDicom = false;
|
||||||
studyMonitor.IsDicomReUpload = false;
|
studyMonitor.IsDicomReUpload = false;
|
||||||
studyMonitor.StudyId = noneDicomStudyId.Value;
|
studyMonitor.StudyId = noneDicomStudyId;
|
||||||
studyMonitor.StudyCode = noneDicomStudy.StudyCode;
|
studyMonitor.StudyCode = noneDicomStudy.StudyCode;
|
||||||
studyMonitor.ArchiveFinishedTime = DateTime.Now;
|
studyMonitor.ArchiveFinishedTime = DateTime.Now;
|
||||||
studyMonitor.IP = _userInfo.IP;
|
studyMonitor.IP = _userInfo.IP;
|
||||||
|
studyMonitor.IsSuccess = true;
|
||||||
|
|
||||||
await _noneDicomStudyRepository.SaveChangesAsync();
|
await _repository.SaveChangesAsync();
|
||||||
|
|
||||||
return ResponseOutput.Ok();
|
return ResponseOutput.Ok();
|
||||||
}
|
}
|
||||||
@@ -540,13 +546,12 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="trialId"></param>
|
/// <param name="trialId"></param>
|
||||||
/// <param name="oSSService"></param>
|
/// <param name="oSSService"></param>
|
||||||
/// <param name="_inspectionFileRepository"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="BusinessValidationFailedException"></exception>
|
/// <exception cref="BusinessValidationFailedException"></exception>
|
||||||
[HttpPost("QCOperation/UploadVisitCheckExcel/{trialId:guid}")]
|
[HttpPost("QCOperation/UploadVisitCheckExcel/{trialId:guid}")]
|
||||||
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
|
||||||
public async Task<IResponseOutput> UploadVisitCheckExcel(Guid trialId, [FromServices] IOSSService oSSService, [FromServices] IRepository<InspectionFile> _inspectionFileRepository)
|
public async Task<IResponseOutput> UploadVisitCheckExcel(Guid trialId, [FromServices] IOSSService oSSService)
|
||||||
{
|
{
|
||||||
|
|
||||||
var fileName = string.Empty;
|
var fileName = string.Empty;
|
||||||
@@ -556,9 +561,9 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
{
|
{
|
||||||
fileName = realFileName;
|
fileName = realFileName;
|
||||||
|
|
||||||
if (!fileName.EndsWith(".xlsx") && !fileName.EndsWith(".xls"))
|
if (!fileName.EndsWith(".xlsx") && !fileName.EndsWith(".csv") && !fileName.EndsWith(".xls"))
|
||||||
{
|
{
|
||||||
//---支持.xlsx、.xls格式的文件上传。
|
//---支持.xlsx、.xls、.csv格式的文件上传。
|
||||||
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_SupportedFormats"]);
|
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_SupportedFormats"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -568,7 +573,7 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
|
|
||||||
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, "InspectionUpload/Check", realFileName);
|
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, "InspectionUpload/Check", realFileName);
|
||||||
|
|
||||||
await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId });
|
await _repository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId });
|
||||||
|
|
||||||
return ossRelativePath;
|
return ossRelativePath;
|
||||||
|
|
||||||
@@ -738,16 +743,11 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
//---请保证上传数据符合模板文件中的样式,且存在有效数据。
|
//---请保证上传数据符合模板文件中的样式,且存在有效数据。
|
||||||
return ResponseOutput.NotOk(_localizer["UploadDownLoad_InvalidData"]);
|
return ResponseOutput.NotOk(_localizer["UploadDownLoad_InvalidData"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
await _mediator.Send(new ConsistencyVerificationRequest() { ETCList = etcCheckList, TrialId = trialId });
|
||||||
// 适合获取结果的
|
|
||||||
//var client = _mediator.CreateRequestClient<ConsistenCheckCommand>();
|
|
||||||
//await client.GetResponse<ConsistenCheckResult>(new ConsistenCheckCommand() { ETCList = etcCheckList, TrialId = trialId });
|
|
||||||
|
|
||||||
//不获取结果,不用定义返回类型
|
|
||||||
await _mediator.Send(new ConsistenCheckCommand() { ETCList = etcCheckList, TrialId = trialId });
|
|
||||||
|
|
||||||
return ResponseOutput.Ok();
|
return ResponseOutput.Ok();
|
||||||
|
|
||||||
@@ -889,6 +889,89 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region 废弃
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载多个医生的所有附件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="doctorIds"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Obsolete]
|
||||||
|
[HttpPost, Route("file/downloadDoctorAttachments")]
|
||||||
|
public async Task<IResponseOutput<UploadFileInfoDTO>> DownloadAttachment(Guid[] doctorIds)
|
||||||
|
{
|
||||||
|
|
||||||
|
var path = await _fileService.CreateDoctorsAllAttachmentZip(doctorIds);
|
||||||
|
|
||||||
|
return ResponseOutput.Ok(new UploadFileInfoDTO
|
||||||
|
{
|
||||||
|
FilePath = path,
|
||||||
|
FullFilePath = path + "?access_token=" + HttpContext.Request.Headers["Authorization"].ToString().Substring(7)
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载指定医生的指定附件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="doctorId">医生Id</param>
|
||||||
|
/// <param name="attachmentIds">要下载的附件Id</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("file/downloadByAttachmentId/{doctorId}")]
|
||||||
|
[Obsolete]
|
||||||
|
public async Task<IResponseOutput<UploadFileInfoDTO>> DownloadAttachmentById(Guid doctorId, Guid[] attachmentIds)
|
||||||
|
{
|
||||||
|
var path = await _fileService.CreateZipPackageByAttachment(doctorId, attachmentIds);
|
||||||
|
return ResponseOutput.Ok(new UploadFileInfoDTO
|
||||||
|
{
|
||||||
|
FilePath = await _fileService.CreateZipPackageByAttachment(doctorId, attachmentIds),
|
||||||
|
FullFilePath = path + "?access_token=" + HttpContext.Request.Headers["Authorization"].ToString().Substring(7)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载医生官方简历 首页 区分 中文和英文
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="language"></param>
|
||||||
|
/// <param name="doctorIds"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("file/downloadOfficialCV/{language}")]
|
||||||
|
[Obsolete]
|
||||||
|
public async Task<IResponseOutput<UploadFileInfoDTO>> DownloadOfficialResume(int language, Guid[] doctorIds)
|
||||||
|
{
|
||||||
|
|
||||||
|
var path = await _fileService.CreateDoctorsAllAttachmentZip(doctorIds);
|
||||||
|
return ResponseOutput.Ok(new UploadFileInfoDTO
|
||||||
|
{
|
||||||
|
FilePath = await _fileService.CreateOfficialResumeZip(language, doctorIds),
|
||||||
|
FullFilePath = path + "?access_token=" + HttpContext.Request.Headers["Authorization"].ToString().Substring(7)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 入组 项目下载简历
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="language"></param>
|
||||||
|
/// <param name="trialId"></param>
|
||||||
|
/// <param name="doctorIdArray"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("enroll/downloadResume/{trialId:guid}/{language}")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[Obsolete]
|
||||||
|
public async Task<IResponseOutput<string>> DownloadResume(int language, Guid trialId, Guid[] doctorIdArray)
|
||||||
|
{
|
||||||
|
var zipPath = await _fileService.CreateOfficialResumeZip(language, doctorIdArray);
|
||||||
|
|
||||||
|
return ResponseOutput.Ok(zipPath);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -981,18 +1064,18 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
}
|
}
|
||||||
var generateUserTypeList = new List<string>() { "CRC", "CRA" };
|
var generateUserTypeList = new List<string>() { "CRC", "CRA" };
|
||||||
|
|
||||||
//if (excelList.Any(t => !generateUserTypeList.Contains(t.UserTypeStr.ToUpper())))
|
if (excelList.Any(t => !generateUserTypeList.Contains(t.UserTypeStr.ToUpper())))
|
||||||
//{
|
{
|
||||||
// //用户类型仅能为 CRC,SR,CRA 请核查Excel数据
|
//用户类型仅能为 CRC,SR,CRA 请核查Excel数据
|
||||||
// throw new BusinessValidationFailedException(_localizer["UploadDownLoad_InvalidUserType"]);
|
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_InvalidUserType"]);
|
||||||
//}
|
}
|
||||||
if (excelList.Count == 0)
|
if (excelList.Count == 0)
|
||||||
{
|
{
|
||||||
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_NoValiddata"]);
|
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_NoValiddata"]);
|
||||||
}
|
}
|
||||||
//处理好 用户类型 和用户类型枚举
|
//处理好 用户类型 和用户类型枚举
|
||||||
var sysUserTypeList = _usertypeRepository.Where(t => t.UserTypeEnum == UserTypeEnum.CRA || t.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Select(t => new { UserTypeId = t.Id, t.UserTypeEnum }).ToList();
|
var sysUserTypeList = _usertypeRepository.Where(t => t.UserTypeEnum == UserTypeEnum.CRA || t.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Select(t => new { UserTypeId = t.Id, t.UserTypeEnum }).ToList();
|
||||||
var siteList = _trialSiteRepository.Where(t => t.TrialId == trialId && siteCodeList.Contains(t.TrialSiteCode)).Select(t => new { t.TrialSiteCode, TrialSiteId = t.Id }).ToList();
|
var siteList = _trialSiteRepository.Where(t => t.TrialId == trialId && siteCodeList.Contains(t.TrialSiteCode)).Select(t => new { t.TrialSiteCode, TrialSiteId= t.Id }).ToList();
|
||||||
|
|
||||||
foreach (var item in excelList)
|
foreach (var item in excelList)
|
||||||
{
|
{
|
||||||
@@ -1016,9 +1099,9 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
item.TrialSiteId = siteList.FirstOrDefault(t => t.TrialSiteCode.ToUpper() == item.TrialSiteCode.ToUpper()).TrialSiteId;
|
item.TrialSiteId = siteList.FirstOrDefault(t => t.TrialSiteCode.ToUpper() == item.TrialSiteCode.ToUpper()).TrialSiteId;
|
||||||
}
|
}
|
||||||
|
|
||||||
var list = excelList.Where(t => t.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator || t.UserTypeEnum == UserTypeEnum.CRA).ToList();
|
|
||||||
|
|
||||||
await _trialSiteSurveyService.ImportGenerateAccountAndJoinTrialAsync(trialId, baseUrl, routeUrl, list);
|
|
||||||
|
await _trialSiteSurveyService.ImportGenerateAccountAndJoinTrialAsync(trialId, baseUrl, routeUrl, excelList.ToList());
|
||||||
|
|
||||||
return ResponseOutput.Ok();
|
return ResponseOutput.Ok();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<SignAssembly>false</SignAssembly>
|
||||||
|
<UserSecretsId>354572d4-9e15-4099-807c-63a2d29ff9f2</UserSecretsId>
|
||||||
|
<LangVersion>default</LangVersion>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<DocumentationFile>.\IRaCIS.Core.API.xml</DocumentationFile>
|
||||||
|
<NoWarn>1701;1702;1591;</NoWarn>
|
||||||
|
<OutputPath>..\bin\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<DocumentationFile>bin\Release\IRaCIS.Core.API.xml</DocumentationFile>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<NoWarn>1701;1702;1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="Controllers\ReviewerApi\**" />
|
||||||
|
<Compile Remove="UploadFile\**" />
|
||||||
|
<Content Remove="Controllers\ReviewerApi\**" />
|
||||||
|
<Content Remove="UploadFile\**" />
|
||||||
|
<EmbeddedResource Remove="Controllers\ReviewerApi\**" />
|
||||||
|
<EmbeddedResource Remove="UploadFile\**" />
|
||||||
|
<None Remove="Controllers\ReviewerApi\**" />
|
||||||
|
<None Remove="UploadFile\**" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Remove="web.config" />
|
||||||
|
<Content Remove="wwwroot\swagger\ui\abp.js" />
|
||||||
|
<Content Remove="wwwroot\swagger\ui\abp.swagger.js" />
|
||||||
|
<Content Remove="wwwroot\swagger\ui\Index.html" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove=".preview.jpg" />
|
||||||
|
<None Remove="GrpcToken.proto" />
|
||||||
|
<None Remove="IRaCIS.Core.API.xml" />
|
||||||
|
<None Remove="Protos\GrpcToken.proto" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ApplicationDefinition Include="GrpcToken.proto" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="wwwroot\swagger\ui\abp.js" />
|
||||||
|
<EmbeddedResource Include="wwwroot\swagger\ui\abp.swagger.js" />
|
||||||
|
<EmbeddedResource Include="wwwroot\swagger\ui\Index.html" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Protobuf Include="Protos\GrpcToken.proto">
|
||||||
|
<GrpcServices>Client</GrpcServices>
|
||||||
|
</Protobuf>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AspNetCoreRateLimit" Version="4.0.1" />
|
||||||
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.2.0" />
|
||||||
|
<PackageReference Include="EasyCaching.InMemory" Version="1.4.1" />
|
||||||
|
<PackageReference Include="EasyCaching.Interceptor.Castle" Version="1.4.1" />
|
||||||
|
<PackageReference Include="Google.Protobuf" Version="3.19.1" />
|
||||||
|
<PackageReference Include="Grpc.Net.Client" Version="2.41.0" />
|
||||||
|
<PackageReference Include="Grpc.Tools" Version="2.42.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Hangfire.Tags.SqlServer" Version="1.8.0" />
|
||||||
|
<PackageReference Include="Invio.Extensions.Authentication.JwtBearer" Version="2.0.1" />
|
||||||
|
<PackageReference Include="LogDashboard" Version="1.4.8" />
|
||||||
|
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="9.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.14.0" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.1" />
|
||||||
|
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="1.1.4" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Email" Version="2.4.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\IRaCIS.Core.Application\IRaCIS.Core.Application.csproj" />
|
||||||
|
<ProjectReference Include="..\IRaCIS.Core.Infra.EFCore\IRaCIS.Core.Infra.EFCore.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Properties\PublishProfiles\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Update="NLog.config">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ProjectExtensions><VisualStudio><UserProperties anonymizetagsetting_1json__JsonSchema="http://json.schemastore.org/jovo-language-model" /></VisualStudio></ProjectExtensions>
|
||||||
|
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ApplicationDefinition Include="GrpcToken.proto" />
|
<ApplicationDefinition Include="GrpcToken.proto" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="wwwroot\swagger\ui\abp.js">
|
<EmbeddedResource Include="wwwroot\swagger\ui\abp.js">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
@@ -61,26 +61,27 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="aliyun-net-sdk-sts" Version="3.1.2" />
|
||||||
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="9.0.0" />
|
||||||
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="ConfigMapFileProvider" Version="2.0.1" />
|
<PackageReference Include="ConfigMapFileProvider" Version="2.0.1" />
|
||||||
|
<PackageReference Include="EasyCaching.Interceptor.Castle" Version="1.9.2" />
|
||||||
|
<PackageReference Include="EasyCaching.Serialization.MessagePack" Version="1.9.2">
|
||||||
|
<TreatAsUsed>true</TreatAsUsed>
|
||||||
|
</PackageReference>
|
||||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.14" />
|
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.14" />
|
||||||
<PackageReference Include="Hangfire.Dashboard.BasicAuthorization" Version="1.0.2" />
|
<PackageReference Include="Hangfire.Dashboard.BasicAuthorization" Version="1.0.2" />
|
||||||
<PackageReference Include="Hangfire.InMemory" Version="0.10.3" />
|
<PackageReference Include="Hangfire.InMemory" Version="0.10.3" />
|
||||||
<PackageReference Include="Hangfire.SqlServer" Version="1.8.14" />
|
<PackageReference Include="Hangfire.SqlServer" Version="1.8.14" />
|
||||||
<PackageReference Include="Invio.Extensions.Authentication.JwtBearer" Version="2.0.1" />
|
<PackageReference Include="Invio.Extensions.Authentication.JwtBearer" Version="2.0.1" />
|
||||||
<PackageReference Include="LogDashboard" Version="1.4.8" />
|
<PackageReference Include="LogDashboard" Version="1.4.8" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.8" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.6" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.2" />
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
|
||||||
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.1.1" />
|
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.0.3" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.7.3" />
|
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.6.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -93,20 +94,67 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Properties\PublishProfiles\" />
|
<Content Update="wwwroot\EmailTemplate\AdminAddUser_US.html">
|
||||||
</ItemGroup>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<ItemGroup>
|
<Content Update="wwwroot\EmailTemplate\AdminResetUser_US.html">
|
||||||
<Content Update="appsettings.json">
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\AdminResetUser.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\SubjectEnrollConfirmOrPDProgress_US.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\TrialDoctorExistJoin_US.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\TrialDoctorFirstJoin.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\TrialSiteSurveyReject.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\TrialSiteSurveyReject_US.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\TrialDoctorExistJoin.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\TrialUserExistJoin_US.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\TrialUserExistJoin.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\AdminAddUser.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\TrialDoctorFirstJoin_US.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\SubjectEnrollConfirmOrPDProgress.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\TrialUserFirstJoin_US.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\UserOptCommon_US.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\UserOptCommon.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\TrialUserFirstJoin.html">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ProjectExtensions>
|
<ItemGroup>
|
||||||
<VisualStudio>
|
<Folder Include="Properties\PublishProfiles\" />
|
||||||
<UserProperties properties_4launchsettings_1json__JsonSchema="" />
|
</ItemGroup>
|
||||||
</VisualStudio>
|
|
||||||
</ProjectExtensions>
|
<ProjectExtensions><VisualStudio><UserProperties properties_4launchsettings_1json__JsonSchema="" /></VisualStudio></ProjectExtensions>
|
||||||
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
<param name="doctorId"></param>
|
<param name="doctorId"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:IRaCIS.Api.Controllers.ExtraController.Login(IRaCIS.Application.Contracts.UserLoginDTO,ZiggyCreatures.Caching.Fusion.IFusionCache,IRaCIS.Core.Application.Service.IUserService,IRaCIS.Core.Application.Auth.ITokenService,IRaCIS.Core.Application.Contracts.IReadingImageTaskService,Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.ServiceVerifyConfigOption},Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.SystemEmailSendConfig},IRaCIS.Core.Application.Service.IMailVerificationService)">
|
<member name="M:IRaCIS.Api.Controllers.ExtraController.Login(IRaCIS.Application.Contracts.UserLoginDTO,EasyCaching.Core.IEasyCachingProvider,IRaCIS.Application.Services.IUserService,IRaCIS.Core.Application.Auth.ITokenService,IRaCIS.Core.Application.Contracts.IReadingImageTaskService,Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.ServiceVerifyConfigOption},IRaCIS.Application.Services.IMailVerificationService)">
|
||||||
<summary> 系统用户登录接口[New] </summary>
|
<summary> 系统用户登录接口[New] </summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.AddOrUpdateTrialInspection(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Application.Contracts.TrialCommand})">
|
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.AddOrUpdateTrialInspection(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Application.Contracts.TrialCommand})">
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
<param name="param"></param>
|
<param name="param"></param>
|
||||||
<returns>新记录Id</returns>
|
<returns>新记录Id</returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.WorkLoadAddOrUpdate(IRaCIS.Core.Application.Service.IDoctorWorkloadService,IRaCIS.Application.Contracts.WorkloadCommand)">
|
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.WorkLoadAddOrUpdate(IRaCIS.Application.Services.IDoctorWorkloadService,IRaCIS.Application.Contracts.WorkloadCommand)">
|
||||||
<summary>
|
<summary>
|
||||||
添加或更新工作量[AUTH]
|
添加或更新工作量[AUTH]
|
||||||
</summary>
|
</summary>
|
||||||
@@ -278,35 +278,24 @@
|
|||||||
<member name="M:IRaCIS.Core.API.Controllers.UploadBaseController.DicomFileUploadAsync(System.Func{System.String,System.IO.Stream,System.Int32,System.Threading.Tasks.Task},System.String)">
|
<member name="M:IRaCIS.Core.API.Controllers.UploadBaseController.DicomFileUploadAsync(System.Func{System.String,System.IO.Stream,System.Int32,System.Threading.Tasks.Task},System.String)">
|
||||||
<summary> 流式上传 Dicom上传 </summary>
|
<summary> 流式上传 Dicom上传 </summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:IRaCIS.Core.API.Controllers.StudyController.ArchiveStudyNew(System.Guid,System.Guid,System.String,System.Nullable{System.Guid},System.Guid,Microsoft.Extensions.Logging.ILogger{IRaCIS.Core.API.Controllers.UploadDownLoadController},IRaCIS.Core.Application.Contracts.IStudyService,Microsoft.AspNetCore.SignalR.IHubContext{IRaCIS.Core.API.UploadHub,IRaCIS.Core.API.IUploadClient},IRaCIS.Core.Application.Contracts.Dicom.IDicomArchiveService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.StudyMonitor})">
|
<member name="M:IRaCIS.Core.API.Controllers.StudyController.ArchiveStudyNew(System.Guid,System.Guid,System.String,System.Nullable{System.Guid},System.Guid,Microsoft.Extensions.Logging.ILogger{IRaCIS.Core.API.Controllers.UploadDownLoadController},EasyCaching.Core.IEasyCachingProvider,IRaCIS.Core.Application.Contracts.IStudyService,Microsoft.AspNetCore.SignalR.IHubContext{IRaCIS.Core.API.UploadHub,IRaCIS.Core.API.IUploadClient},IRaCIS.Core.Application.Contracts.Dicom.IDicomArchiveService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.StudyMonitor})">
|
||||||
<summary>Dicom 归档</summary>
|
<summary>Dicom 归档</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:IRaCIS.Core.API.Controllers.StudyController.PreArchiveStudy(IRaCIS.Core.Application.Contracts.PreArchiveStudyCommand,IRaCIS.Core.Application.Contracts.IStudyService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.StudyMonitor})">
|
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadNoneDicomFile(IRaCIS.Core.API.Controllers.StudyController.UploadNoneDicomFileCommand,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudy},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.StudyMonitor})">
|
||||||
<summary>
|
|
||||||
非dicom 上传预上传接口
|
|
||||||
</summary>
|
|
||||||
<param name="preArchiveStudyCommand"></param>
|
|
||||||
<param name="_studyService"></param>
|
|
||||||
<param name="_studyMonitorRepository"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadNoneDicomFile(IRaCIS.Core.API.Controllers.StudyController.UploadNoneDicomFileCommand,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudy},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.StudyMonitor},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudyFile})">
|
|
||||||
<summary>
|
<summary>
|
||||||
上传非Dicom 文件 支持压缩包 多文件上传
|
上传非Dicom 文件 支持压缩包 多文件上传
|
||||||
</summary>
|
</summary>
|
||||||
<param name="incommand"></param>
|
<param name="incommand"></param>
|
||||||
<param name="_noneDicomStudyRepository"></param>
|
<param name="_noneDicomStudyRepository"></param>
|
||||||
<param name="_studyMonitorRepository"></param>
|
<param name="_studyMonitorRepository"></param>
|
||||||
<param name="_noneDicomStudyFileRepository"></param>
|
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadVisitCheckExcel(System.Guid,IRaCIS.Core.Application.Helper.IOSSService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.InspectionFile})">
|
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadVisitCheckExcel(System.Guid,IRaCIS.Core.Application.Helper.IOSSService)">
|
||||||
<summary>
|
<summary>
|
||||||
一致性核查 excel上传 支持三种格式
|
一致性核查 excel上传 支持三种格式
|
||||||
</summary>
|
</summary>
|
||||||
<param name="trialId"></param>
|
<param name="trialId"></param>
|
||||||
<param name="oSSService"></param>
|
<param name="oSSService"></param>
|
||||||
<param name="_inspectionFileRepository"></param>
|
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
<exception cref="T:IRaCIS.Core.Infrastructure.BusinessValidationFailedException"></exception>
|
<exception cref="T:IRaCIS.Core.Infrastructure.BusinessValidationFailedException"></exception>
|
||||||
</member>
|
</member>
|
||||||
@@ -337,6 +326,38 @@
|
|||||||
<param name="_attachmentrepository"></param>
|
<param name="_attachmentrepository"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.FileController.DownloadAttachment(System.Guid[])">
|
||||||
|
<summary>
|
||||||
|
下载多个医生的所有附件
|
||||||
|
</summary>
|
||||||
|
<param name="doctorIds"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.FileController.DownloadAttachmentById(System.Guid,System.Guid[])">
|
||||||
|
<summary>
|
||||||
|
下载指定医生的指定附件
|
||||||
|
</summary>
|
||||||
|
<param name="doctorId">医生Id</param>
|
||||||
|
<param name="attachmentIds">要下载的附件Id</param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.FileController.DownloadOfficialResume(System.Int32,System.Guid[])">
|
||||||
|
<summary>
|
||||||
|
下载医生官方简历 首页 区分 中文和英文
|
||||||
|
</summary>
|
||||||
|
<param name="language"></param>
|
||||||
|
<param name="doctorIds"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.FileController.DownloadResume(System.Int32,System.Guid,System.Guid[])">
|
||||||
|
<summary>
|
||||||
|
入组 项目下载简历
|
||||||
|
</summary>
|
||||||
|
<param name="language"></param>
|
||||||
|
<param name="trialId"></param>
|
||||||
|
<param name="doctorIdArray"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
<member name="M:IRaCIS.Core.API.Controllers.UploadDownLoadController.DownloadCommonFile(System.String,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.CommonDocument})">
|
<member name="M:IRaCIS.Core.API.Controllers.UploadDownLoadController.DownloadCommonFile(System.String,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.CommonDocument})">
|
||||||
<summary> 通用文件下载 </summary>
|
<summary> 通用文件下载 </summary>
|
||||||
</member>
|
</member>
|
||||||
@@ -362,11 +383,6 @@
|
|||||||
序列化,反序列化的时候,处理时间 时区转换
|
序列化,反序列化的时候,处理时间 时区转换
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:IRaCIS.Core.API.JSONTimeZoneConverter.#ctor(Microsoft.AspNetCore.Http.IHttpContextAccessor)">
|
|
||||||
<summary>
|
|
||||||
序列化,反序列化的时候,处理时间 时区转换
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:IRaCIS.Core.API.NullToEmptyStringResolver.CreateProperties(System.Type,Newtonsoft.Json.MemberSerialization)">
|
<member name="M:IRaCIS.Core.API.NullToEmptyStringResolver.CreateProperties(System.Type,Newtonsoft.Json.MemberSerialization)">
|
||||||
<summary>
|
<summary>
|
||||||
创建属性
|
创建属性
|
||||||
@@ -375,6 +391,18 @@
|
|||||||
<param name="memberSerialization">序列化成员</param>
|
<param name="memberSerialization">序列化成员</param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:IRaCIS.WX.CoreApi.Auth.AuthMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext)">
|
||||||
|
<summary>
|
||||||
|
为了前端 一段时间无操作,需要重新登陆
|
||||||
|
</summary>
|
||||||
|
<param name="httpContext"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="T:TimeZoneAdjustmentMiddleware">
|
||||||
|
<summary>
|
||||||
|
废弃,没用
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="T:ZhaoXi._001.NET5Demo.Practice.WebApi.Utility.Jwt.CustomHSJWTService">
|
<member name="T:ZhaoXi._001.NET5Demo.Practice.WebApi.Utility.Jwt.CustomHSJWTService">
|
||||||
<summary>
|
<summary>
|
||||||
对称可逆加密
|
对称可逆加密
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 废弃,没用
|
||||||
|
/// </summary>
|
||||||
|
public class TimeZoneAdjustmentMiddleware
|
||||||
|
{
|
||||||
|
private readonly RequestDelegate _next;
|
||||||
|
|
||||||
|
public TimeZoneAdjustmentMiddleware(RequestDelegate next)
|
||||||
|
{
|
||||||
|
_next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Invoke(HttpContext context)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(context.Request.ContentType))
|
||||||
|
{
|
||||||
|
// 请求没有内容体,可能是一个没有请求体的请求,比如 GET 请求
|
||||||
|
await _next(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var timeZoneId = "Asia/Shanghai"; // 客户端默认时区
|
||||||
|
|
||||||
|
var timeZoneIdHeaderValue = context.Request.Headers["TimeZoneId"];
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(timeZoneIdHeaderValue))
|
||||||
|
{
|
||||||
|
timeZoneId = timeZoneIdHeaderValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 处理 JSON 请求体中的时间字段
|
||||||
|
if (context.Request.ContentType.StartsWith("application/json"))
|
||||||
|
{
|
||||||
|
var requestBody = await new StreamReader(context.Request.Body).ReadToEndAsync();
|
||||||
|
|
||||||
|
// 使用 JSON.NET 或 System.Text.Json 解析 JSON 请求体
|
||||||
|
// 假设请求体中有一个名为 "dateTime" 的时间字段
|
||||||
|
dynamic jsonData = JsonConvert.DeserializeObject(requestBody);
|
||||||
|
|
||||||
|
if (jsonData.dateTime != null)
|
||||||
|
{
|
||||||
|
if (DateTime.TryParse((string)jsonData.dateTime, out DateTime dateTime))
|
||||||
|
{
|
||||||
|
// 将 JSON 请求体中的时间字段转换为服务器时区的时间
|
||||||
|
var serverTime = TimeZoneInfo.ConvertTime(dateTime, timeZone);
|
||||||
|
jsonData.dateTime = serverTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将修改后的 JSON 请求体重新写入请求流中
|
||||||
|
var jsonBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(jsonData));
|
||||||
|
context.Request.Body = new MemoryStream(jsonBytes);
|
||||||
|
context.Request.ContentLength = jsonBytes.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 处理 URL 表单参数
|
||||||
|
var modifiedQuery = new Dictionary<string, StringValues>();
|
||||||
|
|
||||||
|
foreach (var key in context.Request.Query.Keys)
|
||||||
|
{
|
||||||
|
if (DateTime.TryParse(context.Request.Query[key], out DateTime dateTime))
|
||||||
|
{
|
||||||
|
// 将 URL 表单参数中的时间转换为服务器时区的时间
|
||||||
|
var serverTime = TimeZoneInfo.ConvertTime(dateTime, timeZone);
|
||||||
|
modifiedQuery[key] = new StringValues(serverTime.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
modifiedQuery[key] = context.Request.Query[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Request.Query = new QueryCollection(modifiedQuery);
|
||||||
|
|
||||||
|
// 处理Form请求体中的参数
|
||||||
|
if (context.Request.HasFormContentType)
|
||||||
|
{
|
||||||
|
var modifiedForm = new Dictionary<string, StringValues>();
|
||||||
|
|
||||||
|
foreach (var key in context.Request.Form.Keys)
|
||||||
|
{
|
||||||
|
if (DateTime.TryParse(context.Request.Form[key], out DateTime dateTime))
|
||||||
|
{
|
||||||
|
// 将请求体中的时间转换为服务器时区的时间
|
||||||
|
var serverTime = TimeZoneInfo.ConvertTime(dateTime, timeZone);
|
||||||
|
modifiedForm[key] = new StringValues(serverTime.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
modifiedForm[key] = context.Request.Form[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var newFormCollection = new FormCollection(modifiedForm);
|
||||||
|
|
||||||
|
// 将新的表单集合设置回请求对象
|
||||||
|
context.Request.Form = newFormCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _next(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+25
-121
@@ -4,6 +4,8 @@ using Microsoft.AspNetCore.Hosting;
|
|||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using MediatR;
|
||||||
|
using IRaCIS.Core.Application.MediatR.Handlers;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
using MassTransit.NewIdProviders;
|
using MassTransit.NewIdProviders;
|
||||||
@@ -20,24 +22,15 @@ using Microsoft.AspNetCore.SignalR;
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using IRaCIS.Core.Application.Filter;
|
using IRaCIS.Core.Application.Filter;
|
||||||
using Microsoft.AspNetCore.HttpOverrides;
|
using Microsoft.AspNetCore.HttpOverrides;
|
||||||
using IRaCIS.Core.Application.Service.BackGroundJob;
|
using IRaCIS.Application.Services.BackGroundJob;
|
||||||
using LogDashboard;
|
using LogDashboard;
|
||||||
using FellowOakDicom.Network;
|
using FellowOakDicom.Network;
|
||||||
using IRaCIS.Core.Application.Service.ImageAndDoc;
|
using IRaCIS.Core.Application.Service.ImageAndDoc;
|
||||||
using IP2Region.Net.Abstractions;
|
using IP2Region.Net.Abstractions;
|
||||||
using IP2Region.Net.XDB;
|
using IP2Region.Net.XDB;
|
||||||
using IRaCIS.Core.Application.BusinessFilter;
|
using IRaCIS.Core.Application.BusinessFilter;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using IRaCIS.Core.Infrastructure.Extention;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Microsoft.AspNetCore.Diagnostics;
|
|
||||||
using IRaCIS.Core.Application.MassTransit.Command;
|
|
||||||
using IRaCIS.Core.Application.MassTransit.Consumer;
|
|
||||||
using DocumentFormat.OpenXml.InkML;
|
|
||||||
using IRaCIS.Core.Domain;
|
|
||||||
|
|
||||||
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
|
||||||
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
|
|
||||||
#region 获取环境变量
|
#region 获取环境变量
|
||||||
//以配置文件为准,否则 从url中取环境值(服务以命令行传递参数启动,配置文件配置了就不需要传递环境参数)
|
//以配置文件为准,否则 从url中取环境值(服务以命令行传递参数启动,配置文件配置了就不需要传递环境参数)
|
||||||
var config = new ConfigurationBuilder()
|
var config = new ConfigurationBuilder()
|
||||||
@@ -112,7 +105,7 @@ builder.Services.AddControllers(options =>
|
|||||||
options.Filters.Add<ModelActionFilter>();
|
options.Filters.Add<ModelActionFilter>();
|
||||||
options.Filters.Add<ProjectExceptionFilter>();
|
options.Filters.Add<ProjectExceptionFilter>();
|
||||||
options.Filters.Add<UnitOfWorkFilter>();
|
options.Filters.Add<UnitOfWorkFilter>();
|
||||||
//options.Filters.Add<EncreptApiResultFilter>(10);
|
options.Filters.Add<EncreptApiResultFilter>(10);
|
||||||
options.Filters.Add<LimitUserRequestAuthorization>();
|
options.Filters.Add<LimitUserRequestAuthorization>();
|
||||||
|
|
||||||
|
|
||||||
@@ -123,18 +116,16 @@ builder.Services.AddOptions().Configure<SystemEmailSendConfig>(_configuration.Ge
|
|||||||
builder.Services.AddOptions().Configure<ServiceVerifyConfigOption>(_configuration.GetSection("BasicSystemConfig"));
|
builder.Services.AddOptions().Configure<ServiceVerifyConfigOption>(_configuration.GetSection("BasicSystemConfig"));
|
||||||
builder.Services.AddOptions().Configure<AliyunOSSOptions>(_configuration.GetSection("AliyunOSS"));
|
builder.Services.AddOptions().Configure<AliyunOSSOptions>(_configuration.GetSection("AliyunOSS"));
|
||||||
builder.Services.AddOptions().Configure<ObjectStoreServiceOptions>(_configuration.GetSection("ObjectStoreService"));
|
builder.Services.AddOptions().Configure<ObjectStoreServiceOptions>(_configuration.GetSection("ObjectStoreService"));
|
||||||
builder.Services.AddOptions().Configure<IRCEncreptOption>(_configuration.GetSection("EncrypteResponseConfig"));
|
builder.Services.AddOptions().Configure<EncreptResponseOption>(_configuration.GetSection("EncrypteResponseConfig"));
|
||||||
builder.Services.AddOptions().Configure<SystemPacsConfig>(_configuration.GetSection("SystemPacsConfig"));
|
builder.Services.AddOptions().Configure<SystemPacsConfig>(_configuration.GetSection("SystemPacsConfig"));
|
||||||
|
|
||||||
builder.Services.Configure<IRaCISBasicConfigOption>(_configuration.GetSection("IRaCISBasicConfig"));
|
|
||||||
|
|
||||||
|
|
||||||
//动态WebApi + UnifiedApiResultFilter 省掉控制器代码
|
//动态WebApi + UnifiedApiResultFilter 省掉控制器代码
|
||||||
builder.Services.AddDynamicWebApiSetup();
|
builder.Services.AddDynamicWebApiSetup();
|
||||||
//AutoMapper
|
//AutoMapper
|
||||||
builder.Services.AddAutoMapperSetup();
|
builder.Services.AddAutoMapperSetup();
|
||||||
//EF ORM QueryWithNoLock
|
//EF ORM QueryWithNoLock
|
||||||
builder.Services.AddEFSetup(_configuration, enviromentName);
|
builder.Services.AddEFSetup(_configuration);
|
||||||
//Http 响应压缩
|
//Http 响应压缩
|
||||||
builder.Services.AddResponseCompressionSetup();
|
builder.Services.AddResponseCompressionSetup();
|
||||||
//Swagger Api 文档
|
//Swagger Api 文档
|
||||||
@@ -143,45 +134,9 @@ builder.Services.AddSwaggerSetup();
|
|||||||
builder.Services.AddJWTAuthSetup(_configuration);
|
builder.Services.AddJWTAuthSetup(_configuration);
|
||||||
|
|
||||||
// MediatR 进程内消息 事件解耦 从程序集中 注册命令和handler对应关系
|
// MediatR 进程内消息 事件解耦 从程序集中 注册命令和handler对应关系
|
||||||
//builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<ConsistencyVerificationHandler>());
|
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<ConsistencyVerificationHandler>());
|
||||||
|
|
||||||
#region MassTransit
|
|
||||||
//masstransit组件 也支持MediatR 中介者模式,但是支持分布式,考虑后续,所以在次替代MediatR
|
|
||||||
//参考链接:https://masstransit.io/documentation/concepts/mediator#scoped-mediator
|
|
||||||
builder.Services.AddMediator(cfg =>
|
|
||||||
{
|
|
||||||
cfg.AddConsumer<ConsistencyCheckConsumer>();
|
|
||||||
cfg.AddConsumer<AddSubjectTriggerConsumer>();
|
|
||||||
cfg.AddConsumer<AddSubjectTriggerConsumer2>();
|
|
||||||
//cfg.ConfigureMediator((context, cfg) => cfg.UseHttpContextScopeFilter(context));
|
|
||||||
});
|
|
||||||
|
|
||||||
//添加 MassTransit 和 InMemory 传输
|
|
||||||
builder.Services.AddMassTransit(cfg =>
|
|
||||||
{
|
|
||||||
// 注册消费者
|
|
||||||
cfg.AddConsumer<AddSubjectTriggerConsumer>(); // 替换为你的消费者类
|
|
||||||
cfg.AddConsumer<AddSubjectTriggerConsumer2>();
|
|
||||||
|
|
||||||
// 使用 InMemory 作为消息传递机制
|
|
||||||
cfg.UsingInMemory((context, cfg) =>
|
|
||||||
{
|
|
||||||
// 这里可以进行额外的配置
|
|
||||||
cfg.ConfigureEndpoints(context); // 自动配置所有消费者的端点
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region FusionCache
|
|
||||||
|
|
||||||
builder.Services.AddFusionCache();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
// EasyCaching 缓存
|
// EasyCaching 缓存
|
||||||
//builder.Services.AddEasyCachingSetup(_configuration);
|
builder.Services.AddEasyCachingSetup(_configuration);
|
||||||
|
|
||||||
// hangfire 定时任务框架 有界面,更友好~
|
// hangfire 定时任务框架 有界面,更友好~
|
||||||
builder.Services.AddhangfireSetup(_configuration);
|
builder.Services.AddhangfireSetup(_configuration);
|
||||||
@@ -209,9 +164,6 @@ builder.Services.AddSingleton<IUserIdProvider, IRaCISUserIdProvider>();
|
|||||||
|
|
||||||
builder.Services.AddSingleton<ISearcher>(new Searcher(CachePolicy.Content, Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources, "ip2region.xdb")));
|
builder.Services.AddSingleton<ISearcher>(new Searcher(CachePolicy.Content, Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources, "ip2region.xdb")));
|
||||||
|
|
||||||
//builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
|
|
||||||
//builder.Services.AddProblemDetails();
|
|
||||||
|
|
||||||
|
|
||||||
#region 历史废弃配置
|
#region 历史废弃配置
|
||||||
//builder.Services.AddMemoryCache();
|
//builder.Services.AddMemoryCache();
|
||||||
@@ -235,60 +187,9 @@ var env = app.Environment;
|
|||||||
|
|
||||||
#region 配置中间件
|
#region 配置中间件
|
||||||
|
|
||||||
app.UseMiddleware<EncryptionRequestMiddleware>();
|
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// 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<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);
|
|
||||||
|
|
||||||
|
|
||||||
//}
|
|
||||||
|
|
||||||
// });
|
|
||||||
//});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
//本地化
|
//本地化
|
||||||
app.UseLocalization();
|
app.UseLocalization();
|
||||||
|
|
||||||
@@ -297,11 +198,12 @@ app.UseForwardedHeaders();
|
|||||||
//响应压缩
|
//响应压缩
|
||||||
app.UseResponseCompression();
|
app.UseResponseCompression();
|
||||||
|
|
||||||
|
//app.UseCors(t => t.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
|
||||||
|
|
||||||
//不需要 token 访问的静态文件 wwwroot css, JavaScript, and images don't require authentication.
|
//不需要 token 访问的静态文件 wwwroot css, JavaScript, and images don't require authentication.
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
|
|
||||||
|
app.UseMiddleware<MultiDiskStaticFilesMiddleware>();
|
||||||
|
|
||||||
//LogDashboard
|
//LogDashboard
|
||||||
app.UseLogDashboard("/LogDashboard");
|
app.UseLogDashboard("/LogDashboard");
|
||||||
@@ -309,24 +211,22 @@ app.UseLogDashboard("/LogDashboard");
|
|||||||
//hangfire
|
//hangfire
|
||||||
app.UseHangfireConfig(env);
|
app.UseHangfireConfig(env);
|
||||||
|
|
||||||
#region 暂时废弃
|
|
||||||
|
|
||||||
//app.UseMiddleware<MultiDiskStaticFilesMiddleware>();
|
|
||||||
////限流 中间件
|
////限流 中间件
|
||||||
//app.UseIpRateLimiting();
|
//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);
|
SwaggerSetup.Configure(app, env);
|
||||||
|
|
||||||
@@ -396,6 +296,10 @@ try
|
|||||||
//Log.Logger.Warning($"ContentRootPath——xx:{Path.GetDirectoryName(Path.GetDirectoryName(env.ContentRootPath))}");
|
//Log.Logger.Warning($"ContentRootPath——xx:{Path.GetDirectoryName(Path.GetDirectoryName(env.ContentRootPath))}");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var server = DicomServerFactory.Create<CStoreSCPService>(11112, userState: app.Services);
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,14 +24,6 @@
|
|||||||
},
|
},
|
||||||
"applicationUrl": "http://localhost:6100"
|
"applicationUrl": "http://localhost:6100"
|
||||||
},
|
},
|
||||||
"IRaCIS.Test_IRC_PGSQL": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Test_IRC_PGSQL"
|
|
||||||
},
|
|
||||||
"applicationUrl": "http://localhost:6100"
|
|
||||||
},
|
|
||||||
"IRaCIS.Event_IRC": {
|
"IRaCIS.Event_IRC": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using IRaCIS.Core.Domain.Share;
|
using EasyCaching.Core;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Cors;
|
using Microsoft.AspNetCore.Cors;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
using System;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using EasyCaching.Core;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace IRaCIS.WX.CoreApi.Auth
|
||||||
|
{
|
||||||
|
public class AuthMiddleware
|
||||||
|
{
|
||||||
|
private readonly RequestDelegate _next;
|
||||||
|
private readonly IEasyCachingProvider _provider;
|
||||||
|
public AuthMiddleware(RequestDelegate next, IEasyCachingProvider provider)
|
||||||
|
{
|
||||||
|
_next = next;
|
||||||
|
_provider = provider;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///为了前端 一段时间无操作,需要重新登陆
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpContext"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task Invoke(HttpContext httpContext)
|
||||||
|
{
|
||||||
|
|
||||||
|
var isLogin = httpContext.Request.Path.ToString().ToLower().Contains("login");
|
||||||
|
|
||||||
|
var result = await httpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
|
||||||
|
|
||||||
|
if (!isLogin)
|
||||||
|
{
|
||||||
|
if (!result.Succeeded)
|
||||||
|
{
|
||||||
|
httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||||
|
await httpContext.Response.WriteAsync("Unauthorized");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var toekn = result.Properties.Items[".Token.access_token"];
|
||||||
|
var jwtHandler = new JwtSecurityTokenHandler();
|
||||||
|
JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(toekn);
|
||||||
|
object userId;
|
||||||
|
jwtToken.Payload.TryGetValue("id", out userId);
|
||||||
|
|
||||||
|
var cacheValueExist = await _provider.ExistsAsync(userId.ToString()); //Get<string>(userId.ToString()).ToString();
|
||||||
|
if (!cacheValueExist)
|
||||||
|
{
|
||||||
|
httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||||
|
await httpContext.Response.WriteAsync("Unauthorized");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _provider.SetAsync(userId.ToString(), userId.ToString(), TimeSpan.FromMinutes(15));
|
||||||
|
httpContext.User = result.Principal;
|
||||||
|
await _next.Invoke(httpContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else await _next.Invoke(httpContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using Hangfire;
|
using Hangfire;
|
||||||
using Hangfire.Dashboard;
|
using Hangfire.Dashboard;
|
||||||
using Hangfire.Dashboard.BasicAuthorization;
|
using Hangfire.Dashboard.BasicAuthorization;
|
||||||
using IRaCIS.Core.Application.Service.BackGroundJob;
|
using IRaCIS.Application.Services.BackGroundJob;
|
||||||
using IRaCIS.Core.API.Filter;
|
using IRaCIS.Core.API.Filter;
|
||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Core.Application.Helper;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
|||||||
@@ -20,20 +20,18 @@ namespace IRaCIS.Core.API
|
|||||||
// Set all the common properties available for every request
|
// Set all the common properties available for every request
|
||||||
diagnosticContext.Set("Host", request.Host);
|
diagnosticContext.Set("Host", request.Host);
|
||||||
|
|
||||||
diagnosticContext.Set("Protocol", request.Protocol);
|
|
||||||
diagnosticContext.Set("Scheme", request.Scheme);
|
|
||||||
|
|
||||||
#region old 未用
|
|
||||||
//这种获取的Ip不准 配置服务才行
|
//这种获取的Ip不准 配置服务才行
|
||||||
//diagnosticContext.Set("RequestIP", httpContext.Connection.RemoteIpAddress.ToString());
|
//diagnosticContext.Set("RequestIP", httpContext.Connection.RemoteIpAddress.ToString());
|
||||||
|
|
||||||
//这种方式可以,但是serilog提供了 就不用了
|
//这种方式可以,但是serilog提供了 就不用了
|
||||||
//diagnosticContext.Set("TestIP", httpContext.GetUserIp());
|
//diagnosticContext.Set("TestIP", httpContext.GetUserIp());
|
||||||
|
|
||||||
|
diagnosticContext.Set("Protocol", request.Protocol);
|
||||||
|
diagnosticContext.Set("Scheme", request.Scheme);
|
||||||
|
|
||||||
//这种方式不行 读取的body为空字符串 必须在中间件中读取
|
//这种方式不行 读取的body为空字符串 必须在中间件中读取
|
||||||
//diagnosticContext.Set("RequestBody", await ReadRequestBody(httpContext.Request));
|
//diagnosticContext.Set("RequestBody", await ReadRequestBody(httpContext.Request));
|
||||||
//diagnosticContext.Set("RequestBody", RequestPayload);
|
//diagnosticContext.Set("RequestBody", RequestPayload);
|
||||||
#endregion
|
|
||||||
|
|
||||||
// Only set it if available. You're not sending sensitive data in a querystring right?!
|
// Only set it if available. You're not sending sensitive data in a querystring right?!
|
||||||
if (request.QueryString.HasValue)
|
if (request.QueryString.HasValue)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using AutoMapper.EquivalencyExpression;
|
using AutoMapper.EquivalencyExpression;
|
||||||
using IRaCIS.Core.Application.Service;
|
using IRaCIS.Core.Application.Service;
|
||||||
using IRaCIS.Core.Domain.Models;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace IRaCIS.Core.API
|
namespace IRaCIS.Core.API
|
||||||
@@ -15,11 +14,6 @@ namespace IRaCIS.Core.API
|
|||||||
//AutoMapper.Collection.EntityFrameworkCore
|
//AutoMapper.Collection.EntityFrameworkCore
|
||||||
automapper.AddCollectionMappers();
|
automapper.AddCollectionMappers();
|
||||||
|
|
||||||
|
|
||||||
// 全局忽略 DomainEvents 属性
|
|
||||||
automapper.AddGlobalIgnore(nameof(Entity.DomainEvents));
|
|
||||||
automapper.AddGlobalIgnore(nameof(Entity.DomainCommands));
|
|
||||||
|
|
||||||
#region 会使 IncludeMembers 失效 不能全局使用
|
#region 会使 IncludeMembers 失效 不能全局使用
|
||||||
//mapping an EntityFramework Core DbContext-object.
|
//mapping an EntityFramework Core DbContext-object.
|
||||||
//automapper.UseEntityFrameworkCoreModel<IRaCISDBContext>(services);
|
//automapper.UseEntityFrameworkCoreModel<IRaCISDBContext>(services);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Autofac;
|
using Autofac;
|
||||||
|
using Autofac.Extras.DynamicProxy;
|
||||||
using IRaCIS.Core.Application;
|
using IRaCIS.Core.Application;
|
||||||
using IRaCIS.Core.Application.BackGroundJob;
|
using IRaCIS.Core.Application.BackGroundJob;
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
@@ -9,7 +10,8 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using IRaCIS.Core.Domain.Models;
|
using IRaCIS.Core.Domain.Models;
|
||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
using IRaCIS.Core.Application.Service;
|
using MediatR;
|
||||||
|
using IRaCIS.Application.Services;
|
||||||
using IRaCIS.Application.Interfaces;
|
using IRaCIS.Application.Interfaces;
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
|
|
||||||
@@ -49,7 +51,7 @@ namespace IRaCIS.Core.API
|
|||||||
|
|
||||||
Assembly application = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + "IRaCIS.Core.Application.dll");
|
Assembly application = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + "IRaCIS.Core.Application.dll");
|
||||||
containerBuilder.RegisterAssemblyTypes(application).Where(t => t.FullName.Contains("Service"))
|
containerBuilder.RegisterAssemblyTypes(application).Where(t => t.FullName.Contains("Service"))
|
||||||
.PropertiesAutowired().AsImplementedInterfaces();
|
.PropertiesAutowired().AsImplementedInterfaces().EnableClassInterceptors();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,59 +1,40 @@
|
|||||||
using EntityFramework.Exceptions.SqlServer;
|
using Castle.Core.Logging;
|
||||||
|
using EntityFramework.Exceptions.SqlServer;
|
||||||
using Hangfire.SqlServer;
|
using Hangfire.SqlServer;
|
||||||
using IRaCIS.Core.Application.Triggers;
|
using IRaCIS.Core.Application.Triggers;
|
||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
using IRaCIS.Core.Infra.EFCore.Interceptor;
|
|
||||||
using Medallion.Threading;
|
using Medallion.Threading;
|
||||||
using Medallion.Threading.SqlServer;
|
using Medallion.Threading.SqlServer;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using StackExchange.Redis;
|
using StackExchange.Redis;
|
||||||
|
|
||||||
namespace IRaCIS.Core.API
|
namespace IRaCIS.Core.API
|
||||||
{
|
{
|
||||||
public static class EFSetup
|
public static class EFSetup
|
||||||
{
|
{
|
||||||
public static void AddEFSetup( this IServiceCollection services, IConfiguration configuration,string envName)
|
public static void AddEFSetup( this IServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
|
|
||||||
services.AddHttpContextAccessor();
|
services.AddHttpContextAccessor();
|
||||||
services.AddScoped<IUserInfo, UserInfo>();
|
services.AddScoped<IUserInfo, UserInfo>();
|
||||||
services.AddScoped<ISaveChangesInterceptor, AuditEntityInterceptor>();
|
|
||||||
services.AddScoped<ISaveChangesInterceptor, DispatchDomainEventsInterceptor>();
|
|
||||||
|
|
||||||
|
|
||||||
// First, register a pooling context factory as a Singleton service, as usual:
|
// First, register a pooling context factory as a Singleton service, as usual:
|
||||||
|
|
||||||
//这个注入没有成功--注入是没问题的,构造函数也只是支持参数就好,错在注入的地方不能写DbContext
|
//这个注入没有成功--注入是没问题的,构造函数也只是支持参数就好,错在注入的地方不能写DbContext
|
||||||
//Web程序中通过重用池中DbContext实例可提高高并发场景下的吞吐量, 这在概念上类似于ADO.NET Provider原生的连接池操作方式,具有节省DbContext实例化成本的优点
|
//Web程序中通过重用池中DbContext实例可提高高并发场景下的吞吐量, 这在概念上类似于ADO.NET Provider原生的连接池操作方式,具有节省DbContext实例化成本的优点
|
||||||
services.AddDbContext<IRaCISDBContext>((sp, options) =>
|
services.AddDbContext<IRaCISDBContext>(options =>
|
||||||
{
|
{
|
||||||
|
|
||||||
// 在控制台
|
// 在控制台
|
||||||
//public static readonly ILoggerFactory MyLoggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); });
|
//public static readonly ILoggerFactory MyLoggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); });
|
||||||
var logFactory = LoggerFactory.Create(builder => { builder.AddDebug(); });
|
var logFactory = LoggerFactory.Create(builder => { builder.AddDebug(); });
|
||||||
|
|
||||||
var dbType = configuration.GetSection("ConnectionStrings:Db_Type").Value ;
|
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value,
|
||||||
if (!string.IsNullOrWhiteSpace(dbType) && dbType == "pgsql")
|
contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
|
||||||
{
|
|
||||||
options.UseNpgsql(configuration.GetSection("ConnectionStrings:RemoteNew").Value, contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value, contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//迁移的时候,不生成外键
|
|
||||||
options.ReplaceService<IMigrationsSqlGenerator, NoForeignKeyMigrationsSqlGenerator>();
|
|
||||||
|
|
||||||
|
|
||||||
options.UseLoggerFactory(logFactory);
|
options.UseLoggerFactory(logFactory);
|
||||||
|
|
||||||
@@ -62,7 +43,6 @@ namespace IRaCIS.Core.API
|
|||||||
options.EnableSensitiveDataLogging();
|
options.EnableSensitiveDataLogging();
|
||||||
|
|
||||||
options.AddInterceptors(new QueryWithNoLockDbCommandInterceptor());
|
options.AddInterceptors(new QueryWithNoLockDbCommandInterceptor());
|
||||||
options.AddInterceptors(sp.GetServices<ISaveChangesInterceptor>());
|
|
||||||
|
|
||||||
options.UseProjectables();
|
options.UseProjectables();
|
||||||
|
|
||||||
@@ -75,15 +55,18 @@ namespace IRaCIS.Core.API
|
|||||||
|
|
||||||
options.UseTriggers(triggerOptions =>
|
options.UseTriggers(triggerOptions =>
|
||||||
{
|
{
|
||||||
triggerOptions.AddTrigger<SubjectTrigger>();
|
triggerOptions.AddTrigger<AddSubjectTrigger>();
|
||||||
triggerOptions.AddTrigger<ChallengeStateTrigger>();
|
triggerOptions.AddTrigger<ChallengeStateTrigger>();
|
||||||
|
triggerOptions.AddTrigger<SubjectStateTrigger>();
|
||||||
|
triggerOptions.AddTrigger<AddCRCCliniaclDataTrigger>();
|
||||||
|
triggerOptions.AddTrigger<SubjectVisitCheckPassedTrigger>();
|
||||||
|
triggerOptions.AddTrigger<SubjectVisitFinalVisitTrigger>();
|
||||||
triggerOptions.AddTrigger<SubjectVisitTrigger>();
|
triggerOptions.AddTrigger<SubjectVisitTrigger>();
|
||||||
triggerOptions.AddTrigger<SubjectVisitScanDateTrigger>();
|
|
||||||
triggerOptions.AddTrigger<TrialCriterionSignTrigger>();
|
triggerOptions.AddTrigger<TrialCriterionSignTrigger>();
|
||||||
triggerOptions.AddTrigger<TableQuestionRowTrigger>();
|
triggerOptions.AddTrigger<TableQuestionRowTrigger>();
|
||||||
//triggerOptions.AddTrigger<AddlTrialUserTrigger>();
|
//triggerOptions.AddTrigger<AddlTrialUserTrigger>();
|
||||||
triggerOptions.AddTrigger<VisitTaskIsFrontTaskNeedSignButNotSignTrigger>();
|
triggerOptions.AddTrigger<VisitTaskIsFrontTaskNeedSignButNotSignTrigger>();
|
||||||
triggerOptions.AddTrigger<JudgeVisitTaskTrigger>();
|
triggerOptions.AddTrigger<VisitTaskIbeforeTrigger>();
|
||||||
|
|
||||||
triggerOptions.AddTrigger<UserLogTrigger>();
|
triggerOptions.AddTrigger<UserLogTrigger>();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
using Microsoft.Extensions.Configuration;
|
using EasyCaching.Core;
|
||||||
|
using EasyCaching.Core.Configurations;
|
||||||
|
using EasyCaching.Interceptor.Castle;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace IRaCIS.Core.API
|
namespace IRaCIS.Core.API
|
||||||
@@ -7,18 +10,18 @@ namespace IRaCIS.Core.API
|
|||||||
{
|
{
|
||||||
public static void AddEasyCachingSetup(this IServiceCollection services, IConfiguration configuration)
|
public static void AddEasyCachingSetup(this IServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
//services.AddEasyCaching(options =>
|
services.AddEasyCaching(options =>
|
||||||
//{
|
{
|
||||||
// options.UseInMemory();
|
options.UseInMemory();
|
||||||
|
|
||||||
// //options.UseRedis(configuration, EasyCachingConstValue.DefaultRedisName).WithMessagePack(EasyCachingConstValue.DefaultRedisName);
|
//options.UseRedis(configuration, EasyCachingConstValue.DefaultRedisName).WithMessagePack(EasyCachingConstValue.DefaultRedisName);
|
||||||
|
|
||||||
|
|
||||||
//});
|
});
|
||||||
|
|
||||||
////services.ConfigureCastleInterceptor(options => options.CacheProviderName = EasyCachingConstValue.DefaultRedisName);
|
//services.ConfigureCastleInterceptor(options => options.CacheProviderName = EasyCachingConstValue.DefaultRedisName);
|
||||||
|
|
||||||
//services.ConfigureCastleInterceptor(options => options.CacheProviderName = EasyCachingConstValue.DefaultInMemoryName);
|
services.ConfigureCastleInterceptor(options => options.CacheProviderName = EasyCachingConstValue.DefaultInMemoryName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,41 +11,19 @@ namespace IRaCIS.Core.API
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 序列化,反序列化的时候,处理时间 时区转换
|
/// 序列化,反序列化的时候,处理时间 时区转换
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class JSONTimeZoneConverter(IHttpContextAccessor _httpContextAccessor) : DateTimeConverterBase
|
public class JSONTimeZoneConverter : DateTimeConverterBase
|
||||||
{
|
{
|
||||||
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
|
|
||||||
private TimeZoneInfo _clientTimeZone;
|
private readonly TimeZoneInfo _clientTimeZone;
|
||||||
|
public JSONTimeZoneConverter(IHttpContextAccessor httpContextAccessor)
|
||||||
private string _dateFormat;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public override bool CanConvert(Type objectType)
|
|
||||||
{
|
{
|
||||||
#region 设置语言格式化方式,放在构造函数里面做不到动态切换
|
_httpContextAccessor = httpContextAccessor;
|
||||||
|
|
||||||
|
|
||||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
|
||||||
|
|
||||||
if (!isEn_US)
|
|
||||||
{
|
|
||||||
// Chinese date format
|
|
||||||
_dateFormat = "yyyy-MM-dd HH:mm:ss";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Default or English date format
|
|
||||||
//_dateFormat = "MM/dd/yyyy HH:mm:ss";
|
|
||||||
|
|
||||||
_dateFormat = "yyyy-MM-dd HH:mm:ss";
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 获取当前请求的客户端时区
|
|
||||||
|
|
||||||
|
//默认是UTC
|
||||||
//var timeZoneId = "Etc/UTC";
|
//var timeZoneId = "Etc/UTC";
|
||||||
var timeZoneId = "Asia/Shanghai";
|
var timeZoneId = "Asia/Shanghai";
|
||||||
|
|
||||||
var timeZoneIdHeader = _httpContextAccessor?.HttpContext?.Request?.Headers["TimeZoneId"];
|
var timeZoneIdHeader = _httpContextAccessor?.HttpContext?.Request?.Headers["TimeZoneId"];
|
||||||
|
|
||||||
if (timeZoneIdHeader is not null && !string.IsNullOrEmpty(timeZoneIdHeader.Value))
|
if (timeZoneIdHeader is not null && !string.IsNullOrEmpty(timeZoneIdHeader.Value))
|
||||||
@@ -55,12 +33,12 @@ namespace IRaCIS.Core.API
|
|||||||
|
|
||||||
_clientTimeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
|
_clientTimeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
|
||||||
|
|
||||||
#endregion
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
// 仅支持 DateTime 类型的转换
|
// 仅支持 DateTime 类型的转换
|
||||||
return objectType == typeof(DateTime)|| objectType == typeof(DateTime?);
|
return objectType == typeof(DateTime)|| objectType == typeof(DateTime?);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
@@ -113,10 +91,7 @@ namespace IRaCIS.Core.API
|
|||||||
{
|
{
|
||||||
//第一个参数默认使用系统本地时区 也就是应用服务器的时区
|
//第一个参数默认使用系统本地时区 也就是应用服务器的时区
|
||||||
DateTime clientZoneTime = TimeZoneInfo.ConvertTime(nullableDateTime.Value, _clientTimeZone);
|
DateTime clientZoneTime = TimeZoneInfo.ConvertTime(nullableDateTime.Value, _clientTimeZone);
|
||||||
|
writer.WriteValue(clientZoneTime);
|
||||||
//writer.WriteValue(clientZoneTime);
|
|
||||||
|
|
||||||
writer.WriteValue(clientZoneTime.ToString(_dateFormat));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
using IRaCIS.Core.Domain.Share;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Serialization;
|
|
||||||
using System;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.API
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
//public class CustomContractResolver : DefaultContractResolver
|
|
||||||
//{
|
|
||||||
// protected override JsonContract CreateContract(Type objectType)
|
|
||||||
// {
|
|
||||||
// var contract = base.CreateContract(objectType);
|
|
||||||
|
|
||||||
// // 检查类是否有 LowercaseJsonAttribute 标记
|
|
||||||
// if (objectType.GetCustomAttribute<LowerCamelCaseJsonAttribute>() != null)
|
|
||||||
// {
|
|
||||||
// contract.NamingStrategy = new IRCCamelCaseNamingStrategy();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return contract;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region 废弃
|
|
||||||
|
|
||||||
public class MyDateTimeConverter : JsonConverter<DateTime>
|
|
||||||
{
|
|
||||||
public override DateTime ReadJson(JsonReader reader, Type objectType, DateTime existingValue, bool hasExistingValue, JsonSerializer serializer)
|
|
||||||
{
|
|
||||||
return reader.ReadAsDateTime().Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteJson(JsonWriter writer, DateTime value, JsonSerializer serializer)
|
|
||||||
{
|
|
||||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
|
||||||
|
|
||||||
string dateFormat;
|
|
||||||
if (!isEn_US)
|
|
||||||
{
|
|
||||||
// Chinese date format
|
|
||||||
dateFormat = "yyyy-MM-dd HH:mm:ss";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Default or English date format
|
|
||||||
dateFormat = "MM/dd/yyyy HH:mm:ss";
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.WriteValue(value.ToString(dateFormat));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MyNullableDateTimeConverter : JsonConverter<DateTime?>
|
|
||||||
{
|
|
||||||
public override DateTime? ReadJson(JsonReader reader, Type objectType, DateTime? existingValue, bool hasExistingValue, JsonSerializer serializer)
|
|
||||||
{
|
|
||||||
var val = reader.ReadAsDateTime();
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteJson(JsonWriter writer, DateTime? value, JsonSerializer serializer)
|
|
||||||
{
|
|
||||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
|
||||||
|
|
||||||
string dateFormat;
|
|
||||||
if (!isEn_US)
|
|
||||||
{
|
|
||||||
// Chinese date format
|
|
||||||
dateFormat = "yyyy-MM-dd HH:mm:ss";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Default or English date format
|
|
||||||
dateFormat = "MM/dd/yyyy HH:mm:ss";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value.HasValue)
|
|
||||||
{
|
|
||||||
writer.WriteValue(value.Value.ToString(dateFormat));
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
writer.WriteValue(default(DateTime?));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
@@ -1,16 +1,10 @@
|
|||||||
|
|
||||||
using IRaCIS.Core.API._ServiceExtensions.NewtonsoftJson;
|
using IRaCIS.Core.API._ServiceExtensions.NewtonsoftJson;
|
||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Core.Application.Helper;
|
||||||
using IRaCIS.Core.Domain.Share;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
|
||||||
using System.Text.Json;
|
|
||||||
using Newtonsoft.Json.Serialization;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.API
|
namespace IRaCIS.Core.API
|
||||||
{
|
{
|
||||||
@@ -18,43 +12,34 @@ namespace IRaCIS.Core.API
|
|||||||
{
|
{
|
||||||
public static void AddNewtonsoftJsonSetup(this IMvcBuilder builder, IServiceCollection services)
|
public static void AddNewtonsoftJsonSetup(this IMvcBuilder builder, IServiceCollection services)
|
||||||
{
|
{
|
||||||
|
|
||||||
services.AddHttpContextAccessor();
|
services.AddHttpContextAccessor();
|
||||||
services.AddScoped<JSONTimeZoneConverter>();
|
services.AddScoped<JSONTimeZoneConverter>();
|
||||||
services.AddScoped<ObjectStorePathConvert>();
|
services.AddScoped<CustomStringConverter>();
|
||||||
services.AddScoped<IOSSService, OSSService>();
|
services.AddScoped<IOSSService,OSSService>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
builder.AddNewtonsoftJson(options =>
|
builder.AddNewtonsoftJson(options =>
|
||||||
{
|
{
|
||||||
|
//options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
|
||||||
//大驼峰
|
|
||||||
//options.SerializerSettings.ContractResolver = new DefaultContractResolver();
|
|
||||||
//小驼峰
|
|
||||||
//options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 忽略循环引用
|
// 忽略循环引用
|
||||||
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
|
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
|
||||||
|
//options.SerializerSettings.TypeNameHandling = TypeNameHandling.All;
|
||||||
|
|
||||||
//处理返回给前端 可空类型 给出默认值 比如in? 为null 设置 默认值0
|
//处理返回给前端 可空类型 给出默认值 比如in? 为null 设置 默认值0
|
||||||
options.SerializerSettings.ContractResolver = new NullToEmptyStringResolver();
|
options.SerializerSettings.ContractResolver = new NullToEmptyStringResolver(); //new DefaultContractResolver();// new NullToEmptyStringResolver();
|
||||||
|
// 设置时间格式
|
||||||
// 设置时间格式 isEn_US? "MM/dd/yyyy HH:mm:ss" :
|
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
|
||||||
//options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
|
|
||||||
|
|
||||||
options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
|
options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
|
||||||
|
|
||||||
|
//options.SerializerSettings.Converters.Add(new JSONCustomDateConverter()) ;
|
||||||
|
|
||||||
//二者只能取其一
|
|
||||||
//options.SerializerSettings.Converters.Add(new MyDateTimeConverter());
|
|
||||||
//options.SerializerSettings.Converters.Add(new MyNullableDateTimeConverter());
|
|
||||||
|
|
||||||
//必须放在后面
|
|
||||||
options.SerializerSettings.Converters.Add(services.BuildServiceProvider().GetService<JSONTimeZoneConverter>());
|
options.SerializerSettings.Converters.Add(services.BuildServiceProvider().GetService<JSONTimeZoneConverter>());
|
||||||
|
|
||||||
|
//options.SerializerSettings.Converters.Add(services.BuildServiceProvider().GetService<CustomStringConverter>());
|
||||||
|
|
||||||
|
|
||||||
|
//IsoDateTimeConverter
|
||||||
|
//options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
|
||||||
|
|
||||||
})
|
})
|
||||||
.AddControllersAsServices()//动态webApi属性注入需要
|
.AddControllersAsServices()//动态webApi属性注入需要
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
using IRaCIS.Core.Infrastructure.NewtonsoftJson;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Serialization;
|
using Newtonsoft.Json.Serialization;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.API
|
namespace IRaCIS.Core.API
|
||||||
{
|
{
|
||||||
@@ -32,20 +30,8 @@ namespace IRaCIS.Core.API
|
|||||||
|
|
||||||
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
|
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
|
||||||
{
|
{
|
||||||
// 检查类是否有 LowerCamelCaseJsonAttribute 标记 有的话,属性名小写
|
|
||||||
if (type.GetCustomAttribute<LowerCamelCaseJsonAttribute>() != null)
|
|
||||||
{
|
|
||||||
base.NamingStrategy= new LowerCamelCaseNamingStrategy();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
base.NamingStrategy = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
|
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
|
||||||
|
|
||||||
|
|
||||||
var list= type.GetProperties()
|
var list= type.GetProperties()
|
||||||
.Select(p =>
|
.Select(p =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,13 +9,15 @@ using System.Text.RegularExpressions;
|
|||||||
|
|
||||||
namespace IRaCIS.Core.API._ServiceExtensions.NewtonsoftJson
|
namespace IRaCIS.Core.API._ServiceExtensions.NewtonsoftJson
|
||||||
{
|
{
|
||||||
public class ObjectStorePathConvert : JsonConverter<string>
|
public class CustomStringConverter : JsonConverter<string>
|
||||||
{
|
{
|
||||||
|
//private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
private readonly IOSSService _oSSService;
|
private readonly IOSSService _oSSService;
|
||||||
|
|
||||||
// 构造函数
|
// 构造函数
|
||||||
public ObjectStorePathConvert( IOSSService oSSService)
|
public CustomStringConverter(/*IHttpContextAccessor httpContextAccessor*/ IOSSService oSSService)
|
||||||
{
|
{
|
||||||
|
//_httpContextAccessor = httpContextAccessor;
|
||||||
_oSSService = oSSService;
|
_oSSService = oSSService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,13 +31,13 @@ namespace IRaCIS.Core.API
|
|||||||
|
|
||||||
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("LocalIP", httpContext.Connection.LocalIpAddress.MapToIPv4().ToString()));
|
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("LocalIP", httpContext.Connection.LocalIpAddress.MapToIPv4().ToString()));
|
||||||
|
|
||||||
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("TokenUserRealName", httpContext?.User?.FindFirst(ClaimAttributes.RealName)?.Value));
|
|
||||||
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("TokenUserType", httpContext?.User?.FindFirst(JwtIRaCISClaimType.UserTypeShortName)?.Value));
|
|
||||||
|
|
||||||
|
|
||||||
//这样读取没用
|
//这样读取没用
|
||||||
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("RequestBody", await ReadRequestBody(httpContext.Request)));
|
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("RequestBody", await ReadRequestBody(httpContext.Request)));
|
||||||
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("RequestIP", IPHelper.GetIP(httpContext.Request) ));
|
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("RequestIP", IPHelper.GetIP(httpContext.Request) ));
|
||||||
|
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("TokenUserRealName", httpContext?.User?.FindFirst(ClaimAttributes.RealName)?.Value));
|
||||||
|
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("TokenUserType", httpContext?.User?.FindFirst(JwtIRaCISClaimType.UserTypeShortName)?.Value));
|
||||||
|
|
||||||
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Referer", httpContext.Request.Headers["Referer"].ToString()));
|
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Referer", httpContext.Request.Headers["Referer"].ToString()));
|
||||||
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("request_path", httpContext.Request.Path));
|
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("request_path", httpContext.Request.Path));
|
||||||
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("request_method", httpContext.Request.Method));
|
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("request_method", httpContext.Request.Method));
|
||||||
|
|||||||
@@ -13,16 +13,15 @@
|
|||||||
"ObjectStoreService": {
|
"ObjectStoreService": {
|
||||||
"ObjectStoreUse": "AliyunOSS",
|
"ObjectStoreUse": "AliyunOSS",
|
||||||
"AliyunOSS": {
|
"AliyunOSS": {
|
||||||
"RegionId": "cn-shanghai",
|
"regionId": "cn-shanghai",
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
"internalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
"endpoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||||
"AccessKeyId": "LTAI5tNRTsqL6aWmHkDmTwoH",
|
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
|
||||||
"AccessKeySecret": "7mtGz3qrYWI6JMMBZiLeC119VWicZH",
|
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
|
||||||
"RoleArn": "acs:ram::1899121822495495:role/irc-oss-access",
|
"bucketName": "zy-irc-store",
|
||||||
"BucketName": "zy-irc-store",
|
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
|
||||||
"ViewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
|
"viewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
|
||||||
"Region": "oss-cn-shanghai",
|
"region": "oss-cn-shanghai"
|
||||||
"DurationSeconds": 7200
|
|
||||||
},
|
},
|
||||||
"MinIO": {
|
"MinIO": {
|
||||||
"endpoint": "http://192.168.3.68",
|
"endpoint": "http://192.168.3.68",
|
||||||
@@ -64,8 +63,7 @@
|
|||||||
"CompanyName": "Extensive Imaging",
|
"CompanyName": "Extensive Imaging",
|
||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||||
"CompanyShortName": "Extensive Imaging",
|
"CompanyShortName": "Extensive Imaging",
|
||||||
"CompanyShortNameCN": "展影医疗",
|
"CompanyShortNameCN": "展影医疗"
|
||||||
"IsEnv_US": false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,16 +15,15 @@
|
|||||||
"ObjectStoreService": {
|
"ObjectStoreService": {
|
||||||
"ObjectStoreUse": "AliyunOSS",
|
"ObjectStoreUse": "AliyunOSS",
|
||||||
"AliyunOSS": {
|
"AliyunOSS": {
|
||||||
"RegionId": "cn-shanghai",
|
"regionId": "cn-shanghai",
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
"internalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
"endpoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||||
"AccessKeyId": "LTAI5tNRTsqL6aWmHkDmTwoH",
|
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
|
||||||
"AccessKeySecret": "7mtGz3qrYWI6JMMBZiLeC119VWicZH",
|
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
|
||||||
"RoleArn": "acs:ram::1899121822495495:role/irc-oss-access",
|
"bucketName": "zy-irc-store",
|
||||||
"BucketName": "zy-irc-store",
|
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
|
||||||
"ViewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
|
"viewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
|
||||||
"Region": "oss-cn-shanghai",
|
"region": "oss-cn-shanghai"
|
||||||
"DurationSeconds": 7200
|
|
||||||
},
|
},
|
||||||
"MinIO": {
|
"MinIO": {
|
||||||
"endpoint": "http://192.168.3.68",
|
"endpoint": "http://192.168.3.68",
|
||||||
@@ -68,8 +67,7 @@
|
|||||||
"CompanyName": "Extensive Imaging",
|
"CompanyName": "Extensive Imaging",
|
||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||||
"CompanyShortName": "Extensive Imaging",
|
"CompanyShortName": "Extensive Imaging",
|
||||||
"CompanyShortNameCN": "展影医疗",
|
"CompanyShortNameCN": "展影医疗"
|
||||||
"IsEnv_US": false
|
|
||||||
},
|
},
|
||||||
"SystemPacsConfig": {
|
"SystemPacsConfig": {
|
||||||
"Port": "11113",
|
"Port": "11113",
|
||||||
|
|||||||
@@ -16,36 +16,32 @@
|
|||||||
"ObjectStoreUse": "AliyunOSS",
|
"ObjectStoreUse": "AliyunOSS",
|
||||||
|
|
||||||
"AliyunOSS": {
|
"AliyunOSS": {
|
||||||
"RegionId": "cn-shanghai",
|
"regionId": "cn-shanghai",
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
"internalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
"endPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||||
"AccessKeyId": "LTAI5tRRZehUp2V9pyTPtAJm",
|
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
|
||||||
"AccessKeySecret": "FLizxkHsMm4CGYHtkV8E3PNJJZU7oV",
|
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
|
||||||
"RoleArn": "acs:ram::1899121822495495:role/dev-oss-access",
|
"bucketName": "zy-irc-test-store",
|
||||||
"BucketName": "zy-irc-test-store",
|
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
|
||||||
"ViewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
|
"viewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
|
||||||
"Region": "oss-cn-shanghai",
|
"region": "oss-cn-shanghai"
|
||||||
"DurationSeconds": 7200
|
|
||||||
},
|
},
|
||||||
"MinIO": {
|
"MinIO": {
|
||||||
"EndPoint": "hir-oss.test.extimaging.com",
|
"endPoint": "hir-oss.test.extimaging.com",
|
||||||
"Port": "443",
|
"port": "443",
|
||||||
"UseSSL": true,
|
"useSSL": true,
|
||||||
"AccessKey": "fbStsVYCIPKHQneeqMwD",
|
"accessKey": "fbStsVYCIPKHQneeqMwD",
|
||||||
"SecretKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
|
"secretKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
|
||||||
"BucketName": "irc-test",
|
"bucketName": "irc-test",
|
||||||
"ViewEndpoint": "https://hir-oss.test.extimaging.com/irc-test"
|
"viewEndpoint": "https://hir-oss.test.extimaging.com/irc-test"
|
||||||
},
|
},
|
||||||
"AWS": {
|
"AWS": {
|
||||||
"Region": "us-east-1",
|
"endPoint": "s3.us-east-1.amazonaws.com",
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
"useSSL": true,
|
||||||
"UseSSL": true,
|
"accessKey": "AKIAZQ3DRSOHFPJJ6FEU",
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/uat_s3_access",
|
"secretKey": "l+yjtvV7Z4jiwm/7xCYv30UeUj/SvuqqYzAwjJHf",
|
||||||
"AccessKeyId": "AKIAW3MEAFJX7IPXISP4",
|
"bucketName": "ei-irc-test-store",
|
||||||
"SecretAccessKey": "Pgrg3le5jPxZQ7MR1yYNS30J0XRyJeKVyIIjElXc",
|
"viewEndpoint": "https://ei-irc-test-store.s3.amazonaws.com/"
|
||||||
"BucketName": "ei-med-s3-lili-uat-store",
|
|
||||||
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -88,8 +84,7 @@
|
|||||||
"CompanyName": "Extensive Imaging",
|
"CompanyName": "Extensive Imaging",
|
||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||||
"CompanyShortName": "Extensive Imaging",
|
"CompanyShortName": "Extensive Imaging",
|
||||||
"CompanyShortNameCN": "展影医疗",
|
"CompanyShortNameCN": "展影医疗"
|
||||||
"IsEnv_US": false
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"SystemPacsConfig": {
|
"SystemPacsConfig": {
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"Db_Type": "pgsql",
|
|
||||||
"RemoteNew": "Host=106.14.89.110;Port=5432;Username=sa;Password=pgsql_pwd;Database=Test2_PG",
|
|
||||||
"Hangfire": "Server=106.14.89.110,1435;Database=Test_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
|
||||||
},
|
|
||||||
|
|
||||||
"ObjectStoreService": {
|
|
||||||
|
|
||||||
"ObjectStoreUse": "AliyunOSS",
|
|
||||||
|
|
||||||
"AliyunOSS": {
|
|
||||||
"regionId": "cn-shanghai",
|
|
||||||
"internalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
|
||||||
"endPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
|
|
||||||
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
|
|
||||||
"bucketName": "zy-irc-test-store",
|
|
||||||
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
|
|
||||||
"viewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"region": "oss-cn-shanghai"
|
|
||||||
},
|
|
||||||
"MinIO": {
|
|
||||||
"endPoint": "hir-oss.test.extimaging.com",
|
|
||||||
"port": "443",
|
|
||||||
"useSSL": true,
|
|
||||||
"accessKey": "fbStsVYCIPKHQneeqMwD",
|
|
||||||
"secretKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
|
|
||||||
"bucketName": "irc-test",
|
|
||||||
"viewEndpoint": "https://hir-oss.test.extimaging.com/irc-test"
|
|
||||||
},
|
|
||||||
"AWS": {
|
|
||||||
"endPoint": "s3.us-east-1.amazonaws.com",
|
|
||||||
"useSSL": true,
|
|
||||||
"accessKey": "AKIAZQ3DRSOHFPJJ6FEU",
|
|
||||||
"secretKey": "l+yjtvV7Z4jiwm/7xCYv30UeUj/SvuqqYzAwjJHf",
|
|
||||||
"bucketName": "ei-irc-test-store",
|
|
||||||
"viewEndpoint": "https://ei-irc-test-store.s3.amazonaws.com/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"BasicSystemConfig": {
|
|
||||||
|
|
||||||
"OpenUserComplexPassword": false,
|
|
||||||
|
|
||||||
"OpenSignDocumentBeforeWork": false,
|
|
||||||
|
|
||||||
"OpenTrialRelationDelete": true,
|
|
||||||
|
|
||||||
"OpenLoginLimit": false,
|
|
||||||
|
|
||||||
"LoginMaxFailCount": 5,
|
|
||||||
|
|
||||||
"LoginFailLockMinutes": 1,
|
|
||||||
|
|
||||||
"AutoLoginOutMinutes": 1,
|
|
||||||
|
|
||||||
"OpenLoginMFA": false,
|
|
||||||
|
|
||||||
"ContinuousReadingTimeMin": 120,
|
|
||||||
|
|
||||||
"ReadingRestTimeMin": 10,
|
|
||||||
"IsNeedChangePassWord": true,
|
|
||||||
|
|
||||||
"ChangePassWordDays": 90
|
|
||||||
},
|
|
||||||
|
|
||||||
"SystemEmailSendConfig": {
|
|
||||||
"Port": 465,
|
|
||||||
"Host": "smtp.qiye.aliyun.com",
|
|
||||||
"FromEmail": "test@extimaging.com",
|
|
||||||
"FromName": "Test_IRC",
|
|
||||||
"AuthorizationCode": "SHzyyl2021",
|
|
||||||
"SiteUrl": "http://irc.test.extimaging.com/login",
|
|
||||||
|
|
||||||
"OrganizationName": "Extlmaging",
|
|
||||||
"OrganizationNameCN": "Extlmaging",
|
|
||||||
"CompanyName": "Extensive Imaging",
|
|
||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
|
||||||
"CompanyShortName": "Extensive Imaging",
|
|
||||||
"CompanyShortNameCN": "展影医疗"
|
|
||||||
},
|
|
||||||
|
|
||||||
"SystemPacsConfig": {
|
|
||||||
"Port": "11113",
|
|
||||||
"IP": "106.14.89.110"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,6 +15,18 @@
|
|||||||
|
|
||||||
"ObjectStoreService": {
|
"ObjectStoreService": {
|
||||||
"ObjectStoreUse": "AWS",
|
"ObjectStoreUse": "AWS",
|
||||||
|
"AliyunOSS": {
|
||||||
|
"regionId": "cn-shanghai",
|
||||||
|
"internalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
||||||
|
"endPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||||
|
"accessKeyId": "",
|
||||||
|
"accessKeySecret": "",
|
||||||
|
"bucketName": "zy-irc-test-store",
|
||||||
|
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
|
||||||
|
"viewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
|
||||||
|
"region": "oss-cn-shanghai"
|
||||||
|
},
|
||||||
|
|
||||||
"MinIO": {
|
"MinIO": {
|
||||||
"endPoint": "44.210.231.169",
|
"endPoint": "44.210.231.169",
|
||||||
"port": "9001",
|
"port": "9001",
|
||||||
@@ -26,15 +38,12 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"AWS": {
|
"AWS": {
|
||||||
"Region": "us-east-1",
|
"endPoint": "s3.us-east-1.amazonaws.com",
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
"useSSL": true,
|
||||||
"UseSSL": true,
|
"accessKey": "AKIAW3MEAFJX5P32P6NA",
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/lili_s3_access",
|
"secretKey": "soKfYlzZE11Zi4RyTjXp0myXN0U3U+ka8rT49+B/",
|
||||||
"AccessKeyId": "AKIAW3MEAFJXZ2TZK7GM",
|
"bucketName": "ei-med-s3-lili-store",
|
||||||
"SecretAccessKey": "9MLQCQ1HifEVW1gf068zBRAOb4wNnfrOkvBVByth",
|
"viewEndpoint": "https://ei-med-s3-lili-store.s3.amazonaws.com/"
|
||||||
"BucketName": "ei-med-s3-lili-store",
|
|
||||||
"ViewEndpoint": "https://ei-med-s3-lili-store.s3.amazonaws.com",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"BasicSystemConfig": {
|
"BasicSystemConfig": {
|
||||||
@@ -73,13 +82,7 @@
|
|||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||||
"CompanyShortName": "Elevate Imaging",
|
"CompanyShortName": "Elevate Imaging",
|
||||||
"CompanyShortNameCN": "展影医疗",
|
"CompanyShortNameCN": "展影医疗",
|
||||||
"SiteUrl": "https://lili.elevateimaging.ai/login",
|
"SiteUrl": "https://lili.elevateimaging.ai/login"
|
||||||
"IsEnv_US": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"SystemPacsConfig": {
|
|
||||||
"Port": "104",
|
|
||||||
"IP": "44.210.231.169"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,19 @@
|
|||||||
|
|
||||||
"ObjectStoreService": {
|
"ObjectStoreService": {
|
||||||
|
|
||||||
"ObjectStoreUse": "AWS",
|
"ObjectStoreUse": "MinIO",
|
||||||
|
"AliyunOSS": {
|
||||||
|
"regionId": "cn-shanghai",
|
||||||
|
"internalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
||||||
|
"endPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||||
|
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
|
||||||
|
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
|
||||||
|
"bucketName": "zy-irc-test-store",
|
||||||
|
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
|
||||||
|
"viewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
|
||||||
|
"region": "oss-cn-shanghai"
|
||||||
|
},
|
||||||
|
|
||||||
"MinIO": {
|
"MinIO": {
|
||||||
//"endPoint": "hir-oss.uat.extimaging.com",
|
//"endPoint": "hir-oss.uat.extimaging.com",
|
||||||
//"port": "443",
|
//"port": "443",
|
||||||
@@ -32,26 +44,23 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"AWS": {
|
"AWS": {
|
||||||
"Region": "us-east-1",
|
"endPoint": "s3.us-east-1.amazonaws.com",
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
"useSSL": true,
|
||||||
"UseSSL": true,
|
"accessKey": "AKIAZQ3DRSOHFPJJ6FEU",
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/uat_s3_access",
|
"secretKey": "l+yjtvV7Z4jiwm/7xCYv30UeUj/SvuqqYzAwjJHf",
|
||||||
"AccessKeyId": "AKIAW3MEAFJX7IPXISP4",
|
"bucketName": "ei-irc-test-store",
|
||||||
"SecretAccessKey": "Pgrg3le5jPxZQ7MR1yYNS30J0XRyJeKVyIIjElXc",
|
"viewEndpoint": "https://ei-irc-test-store.s3.amazonaws.com/"
|
||||||
"BucketName": "ei-med-s3-lili-uat-store",
|
|
||||||
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"BasicSystemConfig": {
|
"BasicSystemConfig": {
|
||||||
|
|
||||||
"OpenUserComplexPassword": true,
|
"OpenUserComplexPassword": false,
|
||||||
|
|
||||||
"OpenSignDocumentBeforeWork": true,
|
"OpenSignDocumentBeforeWork": false,
|
||||||
|
|
||||||
"OpenTrialRelationDelete": true,
|
"OpenTrialRelationDelete": true,
|
||||||
|
|
||||||
"OpenLoginLimit": true,
|
"OpenLoginLimit": false,
|
||||||
|
|
||||||
"LoginMaxFailCount": 5,
|
"LoginMaxFailCount": 5,
|
||||||
|
|
||||||
@@ -63,9 +72,7 @@
|
|||||||
"ReadingRestTimeMin": 10,
|
"ReadingRestTimeMin": 10,
|
||||||
"IsNeedChangePassWord": true,
|
"IsNeedChangePassWord": true,
|
||||||
|
|
||||||
"ChangePassWordDays": 90,
|
"ChangePassWordDays": 90
|
||||||
|
|
||||||
"OpenLoginMFA": true
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"SystemEmailSendConfig": {
|
"SystemEmailSendConfig": {
|
||||||
@@ -81,13 +88,7 @@
|
|||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||||
"CompanyShortName": "Elevate Imaging",
|
"CompanyShortName": "Elevate Imaging",
|
||||||
"CompanyShortNameCN": "展影医疗",
|
"CompanyShortNameCN": "展影医疗",
|
||||||
"SiteUrl": "https://lili.test.elevateimaging.ai/login",
|
"SiteUrl": "https://lili.test.elevateimaging.ai/login"
|
||||||
"IsEnv_US": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"SystemPacsConfig": {
|
|
||||||
"Port": "104",
|
|
||||||
"IP": "3.226.182.187"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
//"RemoteNew": "Server=us-mssql-service,1433;Database=US_Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
"RemoteNew": "Server=us-mssql-service,1433;Database=US_Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
//"Hangfire": "Server=us-mssql-service,1433;Database=US_Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
"Hangfire": "Server=us-mssql-service,1433;Database=US_Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||||
|
|
||||||
"RemoteNew": "Server=3.226.182.187,1435;Database=US_Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
//"RemoteNew": "Server=3.226.182.187,1435;Database=US_Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
"Hangfire": "Server=3.226.182.187,1435;Database=US_Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
//"Hangfire": "Server=3.226.182.187,1435;Database=US_Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||||
},
|
},
|
||||||
|
|
||||||
"ObjectStoreService": {
|
"ObjectStoreService": {
|
||||||
@@ -36,22 +36,19 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"AWS": {
|
"AWS": {
|
||||||
"Region": "us-east-1",
|
"endPoint": "s3.us-east-1.amazonaws.com",
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
"useSSL": true,
|
||||||
"UseSSL": true,
|
"accessKey": "AKIAW3MEAFJXUO6XYFYN",
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/uat_s3_access",
|
"secretKey": "AeX5r4xHQH7tNJlTTFVv5/zBXie1Kj+mAayKrukp",
|
||||||
"AccessKeyId": "AKIAW3MEAFJX7IPXISP4",
|
"bucketName": "ei-med-s3-lili-uat-store",
|
||||||
"SecretAccessKey": "Pgrg3le5jPxZQ7MR1yYNS30J0XRyJeKVyIIjElXc",
|
"viewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com/"
|
||||||
"BucketName": "ei-med-s3-lili-uat-store",
|
|
||||||
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com/",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"BasicSystemConfig": {
|
"BasicSystemConfig": {
|
||||||
|
|
||||||
"OpenUserComplexPassword": true,
|
"OpenUserComplexPassword": false,
|
||||||
|
|
||||||
"OpenSignDocumentBeforeWork": true,
|
"OpenSignDocumentBeforeWork": false,
|
||||||
|
|
||||||
"OpenTrialRelationDelete": true,
|
"OpenTrialRelationDelete": true,
|
||||||
|
|
||||||
@@ -69,7 +66,7 @@
|
|||||||
|
|
||||||
"ChangePassWordDays": 90,
|
"ChangePassWordDays": 90,
|
||||||
|
|
||||||
"OpenLoginMFA": false
|
"OpenLoginMFA": true
|
||||||
},
|
},
|
||||||
|
|
||||||
"SystemEmailSendConfig": {
|
"SystemEmailSendConfig": {
|
||||||
@@ -85,13 +82,7 @@
|
|||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||||
"CompanyShortName": "Elevate Imaging",
|
"CompanyShortName": "Elevate Imaging",
|
||||||
"CompanyShortNameCN": "展影医疗",
|
"CompanyShortNameCN": "展影医疗",
|
||||||
"SiteUrl": "https://lili.test.elevateimaging.ai/login",
|
"SiteUrl": "https://lili.test.elevateimaging.ai/login"
|
||||||
"IsEnv_US": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"SystemPacsConfig": {
|
|
||||||
"Port": "104",
|
|
||||||
"IP": "3.226.182.187"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,16 +15,15 @@
|
|||||||
"ObjectStoreUse": "AliyunOSS",
|
"ObjectStoreUse": "AliyunOSS",
|
||||||
|
|
||||||
"AliyunOSS": {
|
"AliyunOSS": {
|
||||||
"RegionId": "cn-shanghai",
|
"regionId": "cn-shanghai",
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
"internalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
"endpoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||||
"AccessKeyId": "LTAI5tRRZehUp2V9pyTPtAJm",
|
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
|
||||||
"AccessKeySecret": "FLizxkHsMm4CGYHtkV8E3PNJJZU7oV",
|
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
|
||||||
"RoleArn": "acs:ram::1899121822495495:role/dev-oss-access",
|
"bucketName": "zy-irc-uat-store",
|
||||||
"BucketName": "zy-irc-uat-store",
|
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
|
||||||
"ViewEndpoint": "https://zy-irc-uat-store.oss-cn-shanghai.aliyuncs.com",
|
"viewEndpoint": "https://zy-irc-uat-store.oss-cn-shanghai.aliyuncs.com",
|
||||||
"Region": "oss-cn-shanghai",
|
"region": "oss-cn-shanghai"
|
||||||
"DurationSeconds": 7200
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"MinIO": {
|
"MinIO": {
|
||||||
@@ -39,17 +38,6 @@
|
|||||||
"secretKey": "DzMaU2L4OXl90uytwOmDXF2encN0Jf4Nxu2XkYqQ",
|
"secretKey": "DzMaU2L4OXl90uytwOmDXF2encN0Jf4Nxu2XkYqQ",
|
||||||
"bucketName": "irc-uat"
|
"bucketName": "irc-uat"
|
||||||
|
|
||||||
},
|
|
||||||
"AWS": {
|
|
||||||
"Region": "us-east-1",
|
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
|
||||||
"UseSSL": true,
|
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/sts_s3_upload",
|
|
||||||
"AccessKeyId": "AKIAW3MEAFJXWRCGSX5Z",
|
|
||||||
"SecretAccessKey": "miais4jQGSd37A+TfBEP11AQM5u/CvotSmznJd8k",
|
|
||||||
"BucketName": "ei-med-s3-lili-uat-store",
|
|
||||||
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com/",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -86,8 +74,7 @@
|
|||||||
"CompanyName": "Extensive Imaging",
|
"CompanyName": "Extensive Imaging",
|
||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||||
"CompanyShortName": "Extensive Imaging",
|
"CompanyShortName": "Extensive Imaging",
|
||||||
"CompanyShortNameCN": "展影医疗",
|
"CompanyShortNameCN": "展影医疗"
|
||||||
"IsEnv_US": false
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"SystemPacsConfig": {
|
"SystemPacsConfig": {
|
||||||
|
|||||||
@@ -43,6 +43,40 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"easycaching": {
|
||||||
|
"inmemory": {
|
||||||
|
"MaxRdSecond": 120,
|
||||||
|
"EnableLogging": false,
|
||||||
|
"LockMs": 5000,
|
||||||
|
"SleepMs": 300,
|
||||||
|
"DBConfig": {
|
||||||
|
"SizeLimit": 10000,
|
||||||
|
"ExpirationScanFrequency": 60,
|
||||||
|
"EnableReadDeepClone": true,
|
||||||
|
"EnableWriteDeepClone": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"redis": {
|
||||||
|
"MaxRdSecond": 120,
|
||||||
|
"EnableLogging": false,
|
||||||
|
"LockMs": 5000,
|
||||||
|
"SleepMs": 300,
|
||||||
|
"dbconfig": {
|
||||||
|
"Password": "xc@123456",
|
||||||
|
"IsSsl": false,
|
||||||
|
"SslHost": null,
|
||||||
|
"ConnectionTimeout": 5000,
|
||||||
|
"AllowAdmin": true,
|
||||||
|
"Endpoints": [
|
||||||
|
{
|
||||||
|
"Host": "47.117.164.182",
|
||||||
|
"Port": 6379
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Database": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"IRaCISImageStore": {
|
"IRaCISImageStore": {
|
||||||
"SwitchingMode": "RemainingDiskCapacity",
|
"SwitchingMode": "RemainingDiskCapacity",
|
||||||
"SwitchingRatio": 80,
|
"SwitchingRatio": 80,
|
||||||
@@ -54,15 +88,13 @@
|
|||||||
"QCChallengeCodePrefix": "Q",
|
"QCChallengeCodePrefix": "Q",
|
||||||
"NoneDicomStudyCodePrefix": "NST",
|
"NoneDicomStudyCodePrefix": "NST",
|
||||||
"DicomStudyCodePrefix": "ST",
|
"DicomStudyCodePrefix": "ST",
|
||||||
"TaskStudyCodePrefix": "P-ST",
|
|
||||||
"SystemSiteCodePrefix": "S",
|
"SystemSiteCodePrefix": "S",
|
||||||
"DefaultPassword": "123456",
|
"DefaultPassword": "123456",
|
||||||
"ImageShareExpireDays": 10
|
"ImageShareExpireDays": 10
|
||||||
},
|
},
|
||||||
|
|
||||||
"EncrypteResponseConfig": {
|
"EncrypteResponseConfig": {
|
||||||
"Base64RSAPublicKey": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0NCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBaHp3T1hYTWYyaEFkS1ZoWHczYUYNCmNaT3QycE1lcmdEaFVrOUdQK2s4VDBrUjFTRVlGVGtzNlkzaEVvL0dRTExqMHZFYVV3bTNhSFNuTTl5NmdLRWoNCmY5cTN6dkoyZzRSQjE4Z0UrTnNWWi9DMkVRZ3k5OWFiWGc5TitGREVlT0NmSjlSRTJPV3JBQ2s0V0RPbFFUdXYNCnhvR2JmcnkwVElSaFBrOGtuYkFmVkZ1and1VXJGblpJZ0ExYXhKZVZ6aDhwcmV1SEgreW1jdHp6NVo4V1pSV3kNCi9ISURHUy90dkg2NUMra2l6cUxRYUpKNHYwODMrRGpaVTBmNzNCdkk5eWt1dW1saXFzY1pvU2preDFOUFJwSkUNCkFtMVFNQ0hMRCtFdzlHT2Vsc2Mwa1ZxdjdaeEF1TkFrMkZuUURNRk1BUmZuUFd0aGVhOGZYVTJsMW9ROWs3WDcNCmN3SURBUUFCDQotLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0NCg==",
|
"IsEnable": true,
|
||||||
"Base64RSAPrivateKey": "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQ0KTUlJRW9nSUJBQUtDQVFFQWh6d09YWE1mMmhBZEtWaFh3M2FGY1pPdDJwTWVyZ0RoVWs5R1ArazhUMGtSMVNFWQ0KRlRrczZZM2hFby9HUUxMajB2RWFVd20zYUhTbk05eTZnS0VqZjlxM3p2SjJnNFJCMThnRStOc1ZaL0MyRVFneQ0KOTlhYlhnOU4rRkRFZU9DZko5UkUyT1dyQUNrNFdET2xRVHV2eG9HYmZyeTBUSVJoUGs4a25iQWZWRnVqd3VVcg0KRm5aSWdBMWF4SmVWemg4cHJldUhIK3ltY3R6ejVaOFdaUld5L0hJREdTL3R2SDY1QytraXpxTFFhSko0djA4Mw0KK0RqWlUwZjczQnZJOXlrdXVtbGlxc2Nab1Nqa3gxTlBScEpFQW0xUU1DSExEK0V3OUdPZWxzYzBrVnF2N1p4QQ0KdU5BazJGblFETUZNQVJmblBXdGhlYThmWFUybDFvUTlrN1g3Y3dJREFRQUJBb0lCQUNDRFoxNi9XWWFYZmpOZA0KQ29pemU2VFJZU2llVzI5eFJic0ExVDV6YUcwVmY4U1NsdFF2Y1dWYmw2UGJUa3BxMkF4MHJDUVB2M2xOSm8vNA0KL3h3QzRlS1E1c1ZLRlFWTXJIbmhISlRxTTJ6UWVpMkJINlBuaEdZcVh0QVhOdzFxejhrSEoyQlFZM3IvN2d5Qw0KcWpZVFVCRDFRem5HeThCanlXOXVIcnNNeDVPRHRRZWxBM3B1TFd1bXZNb3Z1L2JhaDZvTGtOSHY4b0VTdzhGSQ0KTllyTUtscHhFTjZaWUdwSTl2VTZnYUhuTmhEa2ExTHlvUnZ5NnA2dTRLR0FsRTc1VXk4T0dsdncydU5uay9sdg0KSEMyYnY5TnlCRGJpSFNDY0MyK1JXUXMrN0tNWFlwYnBvTVFCR0hqV01GRHVBODFaUCs1TWYxUm9yQUpRNGxrRw0KQnRDQThva0NnWUVBeWY4alBjcFIvQ3dJNU5MYnlwb3ZUWEFHVkFKMmtWRlJVUC9HT2ZOMkFyYWMvL20wdDJ5NA0KemNYVkJZc0pJeHkvVWYxRTFJNFg3VFg3V3NBNGxVNGlPTkwzTnN4dDBEbk1PV2tKUlBPZlF1bW1JaWw5QVRiYQ0KTnRVWFNlTmRoUFFGMGlCb21acFFJYWpSN1RmUnVBbzR6dmpTLzkzeXZZY0lIWU1zM0tjR00ya0NnWUVBcTJPbg0KZlp0RmhLTElGanVlRzRrNklGTWdjbytEUUh5TTFWSUp5Tk05K1o2TEgybzI5eDJCaSs2Qm82M2NKUjQ2STZncQ0KNWUrSTBvdzZRYmNQeTZUNHFSQ0o3Ujd6MllkdEw4eXdJTkNYS3U0cC9qaFNqNWJ1TzFJWlI3ZStSV29CakNtUQ0KWFd0ZVBCbldqWVlLdVRCazROc2FXV09GTXg1QndKdUp2MjBnQ0hzQ2dZQlV4QnFYM1lWV0cyeUlDZXh1TXhIUw0KbjBZb2p2Z090MTgyYkg5VTVsUUpnM1NTL3NqVmlHeHMvYTROSzNGa0tMWW93KzNVZk9TUmlPdTRBNTQ3R1pURw0KMzlFYVQrTnRWRFBkaTdSMkdQNG1hRUp0WjVlcm9NY2w1M3BrYVdOZlhiL3JrK29STzI2UkVYVTI1UXUrL1pzbA0KVDhuTDBlb0JtdDdPODdNcHpYV09zUUtCZ0ZxVGFQSGx2RUNUY3FEbFV2S0VmRmFXOTkvelhrOFhRNnA5RjdTdA0KaHVSRDJJeDZxcC9BVlRWcGo5Tzd6MHRDaFVGUTM1THpHMkVDUU10My9uNEdLbS9XMEwyakRRWWFIeWNTeXNZYw0KMXJjV2ROVG9XU0dQaDBtTVl0WFhFbFJHNkpoMVl0a3NJL29wUVkwN21MRTBGU3dNUHdtY29jbFpKVEN3UW9VTA0KRzlHL0FvR0FWM25kcWcydnUyR0x4TlRUbm1UTWRJNFB3UzBmN0V4VnVNUnRicGZyOWhKNzlDakVNTGFXQ1FsNg0KeE43TElMTnArNVQwQW1DZVBqcitkbnJkRUNidFZPTDFybDc3Z0krRkwzaVVqYmZmMVZqa0N3M0x6K3cyb1FFdA0KbGE4aTZrL1NRK01iYkRPaWRJOVczdlN6MmlJRlZobWJiK1Q2SlZwakxqNjlkblM3eUxZPQ0KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0NCg==",
|
|
||||||
"IsResponseEncreptEnable": true,
|
|
||||||
"ApiPathList": [
|
"ApiPathList": [
|
||||||
"/test/get"
|
"/test/get"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
尊敬的 {0} ,您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{company abbreviation}为您添加了账户,账户信息如下:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
用户名: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
角色: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
首次登陆前,请通过该链接修改您的账户信息:
|
||||||
|
<a href='{3}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
|
||||||
|
初始化账号信息
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
Dear {0} ,
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{company abbreviation} has created an account for you. The account information is as follows:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
User ID: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Role: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Before logging in for the first time, please modify the account information through this link:
|
||||||
|
<a href='{3}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
|
||||||
|
Initialize account information
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>Best regards,</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
尊敬的 {0} ,您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{company abbreviation}将您的账户密码已重置,账户信息如下:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
用户名: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
角色: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
密码: {3}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
Dear {0} ,
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{company abbreviation} has reset your account password, and the account information is as follows:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
User ID: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Role: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Password: {3}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>Best regards,</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
感谢您使用展影云平台。
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{0}。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
Dear:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
Thank you for using {company abbreviation} Cloud System.
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{0}。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>Best regards,</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
尊敬的 {0} ,您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{company abbreviation}作为 [{1} (试验方案号:{2 })] 项目的供应商,诚邀您参加该项目阅片相关工作。
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
该项目采用电子化工作流,系统及您的账号信息如下:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
项目编号: {3}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验方案号: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验名称: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
用户名: {4}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
角色: {5}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
系统登录地址:
|
||||||
|
<a href='{6}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
|
||||||
|
点击跳转
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
Dear {0},
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
|
||||||
|
{company abbreviation} invites you to participate in the IRC work of a trial ({1} , {2}).
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
Your account information is as follows:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
Trial ID: {3}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Protocol ID: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Study Name: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
User ID: {4}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Role: {5}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Login URL:
|
||||||
|
<a href='{6}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
|
||||||
|
Click to login
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>Best regards,</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
尊敬的 {0} ,您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{company abbreviation}作为 [{1} (试验方案号:{2 })] 项目的IRC供应商,诚邀您参加该项目IRC阅片相关工作,欢迎您提供指导和建议,非常感谢!
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
该项目采用电子化工作流,系统及您的账号信息如下:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
项目编号: {3}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验方案号: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验名称: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
用户名: {4}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
角色: {5}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
首次登陆前,请通过该链接修改您的账户信息:
|
||||||
|
<a href='{6}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
|
||||||
|
初始化账号信息
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
Dear {0},
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{company abbreviation} invites you to participate in the IRC work of a trial ({1}, {2}).
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
Your account information is as follows:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
Trial ID: {3}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Protocol ID: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Study Name: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
User ID: {4}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Role: {5}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Before logging in for the first time, please modify the account information through this link:
|
||||||
|
<a href='{6}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
|
||||||
|
Initialize account information
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>Best regards,</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
尊敬的 {0} ,您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
您填写的中心调研表被驳回,详细信息如下:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
项目编号: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验方案号: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验名称: {3}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
中心编号: {4}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
中心名称: {5}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
驳回原因: {6}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<a href='{7}' style='margin-left:60px;font-size:14px;padding: 10px;text-decoration: none;display:{8} ;height: 40px;width: 140px;background: #00D1B2;color:#fff;border-radius: 5px;line-height: 40px;text-align: center;margin-bottom: 100px;'>
|
||||||
|
登陆并查看
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
Dear {0} ,
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
The site survey form you filled in has been rejected. The details are as follows:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
Trial ID: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Protocol ID: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Study Name: {3}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Site ID: {4}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Site name: {5}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Reason for rejection: {6}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<a href='{7}' style='margin-left:60px;font-size:14px;padding: 10px;text-decoration: none;display:{8} ;height: 40px;width: 140px;background: #00D1B2;color:#fff;border-radius: 5px;line-height: 40px;text-align: center;margin-bottom: 100px;'>
|
||||||
|
Login and view
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>Best regards,</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
尊敬的 {0} ,您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{company abbreviation}作为 [{1} (试验方案号:{2 })] 项目的供应商,诚邀您参加该项目相关工作,欢迎您提供指导和建议,非常感谢!
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
该项目采用电子化工作流,系统及您的账号信息如下:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
项目编号: {3}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验方案号: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验名称: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
用户名: {4}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
角色: {5}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
系统登录地址:
|
||||||
|
<a href='{6}' style='margin-left:5px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
|
||||||
|
点击跳转
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
Dear {0},
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;font-size: 16px'>
|
||||||
|
{company abbreviation} invites you to participate in the IRC work of a trial ({1}, {2}).
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
Your account information is as follows:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
Trial ID: {3}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Protocol ID: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Study Name: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
User ID: {4}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Role: {5}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Login URL:
|
||||||
|
<a href='{6}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
|
||||||
|
Click to login
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>Best regards,</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
尊敬的 {0} ,您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{company abbreviation}作为 [{1} (试验方案号:{2 })] 项目的IRC供应商,诚邀您参加该项目IRC相关工作,欢迎您提供指导和建议,非常感谢!
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
该项目采用电子化工作流,系统及您的账号信息如下:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
项目编号: {3}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验方案号: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验名称: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
用户名: {4}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
角色: {5}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
首次登陆前,请通过该链接修改您的账户信息:
|
||||||
|
<a href='{6}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
|
||||||
|
初始化账号信息
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
Dear {0},
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{company abbreviation} invites you to participate in the IRC work of a trial ({1}, {2}).
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
Your account information is as follows:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
Trial ID: {3}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Protocol ID: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Study Name: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
User ID: {4}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Role: {5}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Before logging in for the first time, please modify the account information through this link:
|
||||||
|
<a href='{6}' style='margin-left:1px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
|
||||||
|
Initialize the account information
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>Best regards,</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
{0}您好,
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
感谢您使用展影云平台。
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{1},验证码是: <span style="font-weight:bold">{2}</span>。
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
请在3分钟内输入该验证码,进行后续操作
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
Dear {0},
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{1}
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
The verification code is <span style="font-weight:bold">{2}</span>.
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
This code will expire in 3 minutes.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>Best regards,</div>
|
||||||
|
<div style="font-size: 14px;">{company}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -31,9 +31,9 @@ namespace IRaCIS.Core.Application.Auth
|
|||||||
Id = user.Id,
|
Id = user.Id,
|
||||||
FullName = user.UserName,
|
FullName = user.UserName,
|
||||||
RealName = user.RealName,
|
RealName = user.RealName,
|
||||||
UserTypeEnum = user.UserTypeEnum,
|
UserTypeEnum=user.UserTypeEnum,
|
||||||
UserTypeId = user.UserTypeId,
|
UserTypeId=user.UserTypeId,
|
||||||
IsTestUser = user.IsTestUser,
|
IsTestUser=user.IsTestUser,
|
||||||
Code = user.Code,
|
Code = user.Code,
|
||||||
PermissionStr = user.PermissionStr,
|
PermissionStr = user.PermissionStr,
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
namespace IRaCIS.Core.Application.Auth
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Auth
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Microsoft.IdentityModel.Tokens;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Auth
|
namespace IRaCIS.Core.Application.Auth
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using IRaCIS.Core.Domain.Share;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using System.IdentityModel.Tokens.Jwt;
|
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Auth
|
namespace IRaCIS.Core.Application.Auth
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,56 +1,97 @@
|
|||||||
using Hangfire;
|
using EasyCaching.Core;
|
||||||
|
using Hangfire;
|
||||||
using Hangfire.Storage;
|
using Hangfire.Storage;
|
||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Core.Application.Helper;
|
||||||
|
using IRaCIS.Core.Application.Service;
|
||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using IRaCIS.Core.Infrastructure;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using SharpCompress.Common;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Service.BackGroundJob
|
namespace IRaCIS.Application.Services.BackGroundJob
|
||||||
{
|
{
|
||||||
|
|
||||||
public interface IIRaCISHangfireJob
|
public interface IIRaCISHangfireJob
|
||||||
{
|
{
|
||||||
|
|
||||||
//Task MemoryCacheTrialStatusAsync();
|
Task MemoryCacheTrialStatusAsync();
|
||||||
|
|
||||||
Task InitHangfireJobTaskAsync();
|
Task InitHangfireJobTaskAsync();
|
||||||
|
|
||||||
}
|
}
|
||||||
public class IRaCISCHangfireJob(ILogger<IRaCISCHangfireJob> _logger,
|
public class IRaCISCHangfireJob : IIRaCISHangfireJob
|
||||||
IRepository<Internationalization> _internationalizationRepository,
|
|
||||||
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository
|
|
||||||
) : IIRaCISHangfireJob
|
|
||||||
{
|
{
|
||||||
public static string JsonFileFolder = Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources);
|
public static string JsonFileFolder = Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources);
|
||||||
|
|
||||||
|
private readonly IRepository<Trial> _trialRepository;
|
||||||
|
private readonly IEasyCachingProvider _provider;
|
||||||
|
private readonly ILogger<IRaCISCHangfireJob> _logger;
|
||||||
|
private readonly IRepository<SystemAnonymization> _systemAnonymizationRepository;
|
||||||
|
private readonly IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository;
|
||||||
|
private readonly IRepository<Internationalization> _internationalizationRepository;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public IRaCISCHangfireJob(IRepository<Trial> trialRepository, ILogger<IRaCISCHangfireJob> logger, IEasyCachingProvider provider, IRepository<TrialEmailNoticeConfig> trialEmailNoticeConfigRepository, IRepository<Internationalization> internationalizationRepository, IRepository<SystemAnonymization> systemAnonymizationRepository)
|
||||||
|
{
|
||||||
|
_trialRepository = trialRepository;
|
||||||
|
_provider = provider;
|
||||||
|
_logger = logger;
|
||||||
|
_trialEmailNoticeConfigRepository = trialEmailNoticeConfigRepository;
|
||||||
|
_internationalizationRepository = internationalizationRepository;
|
||||||
|
_systemAnonymizationRepository = systemAnonymizationRepository;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task InitHangfireJobTaskAsync()
|
public async Task InitHangfireJobTaskAsync()
|
||||||
{
|
{
|
||||||
_logger.LogInformation("项目启动 hangfire 任务初始化 执行开始~");
|
_logger.LogInformation("项目启动 hangfire 任务初始化 执行开始~");
|
||||||
|
|
||||||
//初始化国际化
|
|
||||||
|
//项目状态 立即加载到缓存中
|
||||||
|
await MemoryCacheTrialStatusAsync();
|
||||||
|
|
||||||
|
await MemoryCacheAnonymizeData();
|
||||||
|
|
||||||
|
|
||||||
|
//创建项目缓存 定时任务
|
||||||
|
HangfireJobHelper.AddOrUpdateInitCronJob<IIRaCISHangfireJob>("RecurringJob_Cache_TrialState", t => t.MemoryCacheTrialStatusAsync(), Cron.Daily());
|
||||||
|
|
||||||
|
//初始化
|
||||||
|
|
||||||
await InternationalizationHelper.InitInternationlizationDataAndWatchJsonFileAsync(_internationalizationRepository);
|
await InternationalizationHelper.InitInternationlizationDataAndWatchJsonFileAsync(_internationalizationRepository);
|
||||||
|
|
||||||
//创建邮件定时任务
|
//创建邮件定时任务
|
||||||
await InitSysAndTrialCronJobAsync();
|
await InitSysAndTrialCronJobAsync();
|
||||||
|
|
||||||
#region 废弃
|
|
||||||
////项目状态 立即加载到缓存中
|
|
||||||
//await MemoryCacheTrialStatusAsync();
|
|
||||||
|
|
||||||
////await MemoryCacheAnonymizeData();
|
|
||||||
|
|
||||||
|
|
||||||
////创建项目缓存 定时任务
|
|
||||||
//HangfireJobHelper.AddOrUpdateInitCronJob<IIRaCISHangfireJob>("RecurringJob_Cache_TrialState", t => t.MemoryCacheTrialStatusAsync(), Cron.Daily());
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
_logger.LogInformation("项目启动 hangfire 任务初始化 执行结束");
|
_logger.LogInformation("项目启动 hangfire 任务初始化 执行结束");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存项目状态
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task MemoryCacheTrialStatusAsync()
|
||||||
|
{
|
||||||
|
|
||||||
|
var list = await _trialRepository.Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr })
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task MemoryCacheAnonymizeData()
|
||||||
|
{
|
||||||
|
var systemAnonymizationList = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync();
|
||||||
|
|
||||||
|
_provider.Set(StaticData.Anonymize.Anonymize_AddFixedFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed).ToList(), TimeSpan.FromDays(7));
|
||||||
|
_provider.Set(StaticData.Anonymize.Anonymize_AddIRCInfoFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed == false).ToList(), TimeSpan.FromDays(7));
|
||||||
|
_provider.Set(StaticData.Anonymize.Anonymize_FixedField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed).ToList(), TimeSpan.FromDays(7));
|
||||||
|
_provider.Set(StaticData.Anonymize.Anonymize_IRCInfoField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed == false).ToList(), TimeSpan.FromDays(7));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -95,9 +136,6 @@ namespace IRaCIS.Core.Application.Service.BackGroundJob
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.BackGroundJob
|
namespace IRaCIS.Core.Application.BackGroundJob
|
||||||
{
|
{
|
||||||
public interface IObtainTaskAutoCancelJob
|
public interface IObtainTaskAutoCancelJob
|
||||||
{
|
{
|
||||||
Task CancelQCObtaion(Guid subjectVisitId, DateTime startTime);
|
Task CancelQCObtaion(Guid subjectVisitId,DateTime startTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ObtainTaskAutoCancelJob : IObtainTaskAutoCancelJob
|
public class ObtainTaskAutoCancelJob : IObtainTaskAutoCancelJob
|
||||||
@@ -29,7 +30,7 @@ namespace IRaCIS.Core.Application.BackGroundJob
|
|||||||
|
|
||||||
var success = await _subjectVisitRepository.SaveChangesAsync();
|
var success = await _subjectVisitRepository.SaveChangesAsync();
|
||||||
|
|
||||||
_logger.LogWarning($"任务建立时间:{startTime} 取消时间:{DateTime.Now} 取消 受试者访视:{subjectVisitId}success:{success}");
|
_logger.LogWarning($"任务建立时间:{startTime} 取消时间:{DateTime.Now} 取消 受试者访视:{ subjectVisitId }success:{success}");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using IRaCIS.Core.Application.Service.BusinessFilter;
|
using IRaCIS.Application.Services.BusinessFilter;
|
||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using Panda.DynamicWebApi;
|
using Panda.DynamicWebApi;
|
||||||
using Panda.DynamicWebApi.Attributes;
|
using Panda.DynamicWebApi.Attributes;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using ZiggyCreatures.Caching.Fusion;
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Service
|
namespace IRaCIS.Core.Application
|
||||||
{
|
{
|
||||||
|
|
||||||
#pragma warning disable CS8618
|
#pragma warning disable CS8618
|
||||||
@@ -26,13 +26,13 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
|
|
||||||
public IUserInfo _userInfo { get; set; }
|
public IUserInfo _userInfo { get; set; }
|
||||||
|
|
||||||
|
public IRepository _repository { get; set; }
|
||||||
|
|
||||||
public IStringLocalizer _localizer { get; set; }
|
public IStringLocalizer _localizer { get; set; }
|
||||||
|
|
||||||
public IWebHostEnvironment _hostEnvironment { get; set; }
|
public IWebHostEnvironment _hostEnvironment { get; set; }
|
||||||
|
|
||||||
public IFusionCache _fusionCache { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public static IResponseOutput Null404NotFound<TEntity>(TEntity? businessObject) where TEntity : class
|
public static IResponseOutput Null404NotFound<TEntity>(TEntity? businessObject) where TEntity : class
|
||||||
@@ -51,6 +51,8 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
[MemberNotNull(nameof(_userInfo))]
|
[MemberNotNull(nameof(_userInfo))]
|
||||||
public IUserInfo _userInfo { get; set; }
|
public IUserInfo _userInfo { get; set; }
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(_repository))]
|
||||||
|
public IRepository _repository { get; set; }
|
||||||
|
|
||||||
[MemberNotNull(nameof(_localizer))]
|
[MemberNotNull(nameof(_localizer))]
|
||||||
public IStringLocalizer _localizer { get; set; }
|
public IStringLocalizer _localizer { get; set; }
|
||||||
@@ -58,9 +60,6 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
[MemberNotNull(nameof(_hostEnvironment))]
|
[MemberNotNull(nameof(_hostEnvironment))]
|
||||||
public IWebHostEnvironment _hostEnvironment { get; set; }
|
public IWebHostEnvironment _hostEnvironment { get; set; }
|
||||||
|
|
||||||
[MemberNotNull(nameof(_fusionCache))]
|
|
||||||
public IFusionCache _fusionCache { get; set; }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -76,11 +75,13 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
[MemberNotNull(nameof(_userInfo))]
|
[MemberNotNull(nameof(_userInfo))]
|
||||||
public IUserInfo _userInfo { get; set; }
|
public IUserInfo _userInfo { get; set; }
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(_repository))]
|
||||||
|
public IRepository _repository { get; set; }
|
||||||
|
|
||||||
[MemberNotNull(nameof(_localizer))]
|
[MemberNotNull(nameof(_localizer))]
|
||||||
public IStringLocalizer _localizer { get; set; }
|
public IStringLocalizer _localizer { get; set; }
|
||||||
|
|
||||||
[MemberNotNull(nameof(_fusionCache))]
|
|
||||||
public IFusionCache _fusionCache { get; set; }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,9 +93,9 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
|
|
||||||
public IUserInfo _userInfo { get; set; }
|
public IUserInfo _userInfo { get; set; }
|
||||||
|
|
||||||
public IStringLocalizer _localizer { get; set; }
|
public IRepository _repository { get; set; }
|
||||||
|
|
||||||
public IFusionCache _fusionCache { get; set; }
|
public IStringLocalizer _localizer { get; set; }
|
||||||
|
|
||||||
public static IResponseOutput Null404NotFound<TEntity>(TEntity? businessObject) where TEntity : class
|
public static IResponseOutput Null404NotFound<TEntity>(TEntity? businessObject) where TEntity : class
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
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 EncreptApiResultFilter : IAsyncResultFilter
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly IOptionsMonitor<EncreptResponseOption> _encreptResponseMonitor;
|
||||||
|
|
||||||
|
public EncreptApiResultFilter(IOptionsMonitor<EncreptResponseOption> encreptResponseMonitor)
|
||||||
|
{
|
||||||
|
_encreptResponseMonitor = encreptResponseMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(_encreptResponseMonitor.CurrentValue.IsEnable)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (context.Result is ObjectResult objectResult)
|
||||||
|
{
|
||||||
|
var statusCode = objectResult.StatusCode ?? context.HttpContext.Response.StatusCode;
|
||||||
|
|
||||||
|
var objectValue = objectResult.Value;
|
||||||
|
|
||||||
|
|
||||||
|
if (objectValue is IResponseOutput)
|
||||||
|
{
|
||||||
|
var responseOutput = objectValue as IResponseOutput<object>;
|
||||||
|
|
||||||
|
var path = context.HttpContext?.Request.Path.Value?.ToLower();
|
||||||
|
|
||||||
|
|
||||||
|
if(!string.IsNullOrEmpty(path) && path.Length>5 && _encreptResponseMonitor.CurrentValue.ApiPathList.Contains(path.ToLower()))
|
||||||
|
{
|
||||||
|
|
||||||
|
if(responseOutput.IsSuccess)
|
||||||
|
{
|
||||||
|
responseOutput.Code = ApiResponseCodeEnum.ResultEncrepted;
|
||||||
|
responseOutput.Data = JsonConvert.SerializeObject(Convert.ToBase64String(Encoding.UTF8.GetBytes(responseOutput.Data.ToString())));
|
||||||
|
|
||||||
|
objectResult.Value = responseOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
await next.Invoke();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
using IRaCIS.Core.Domain.Share;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.BusinessFilter;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 测试加密API 返回的结果
|
|
||||||
/// </summary>
|
|
||||||
public class EncreptApiResultFilter : IAsyncResultFilter
|
|
||||||
{
|
|
||||||
private readonly IOptionsMonitor<IRCEncreptOption> _encreptResponseMonitor;
|
|
||||||
|
|
||||||
public EncreptApiResultFilter(IOptionsMonitor<IRCEncreptOption> encreptResponseMonitor)
|
|
||||||
{
|
|
||||||
_encreptResponseMonitor = encreptResponseMonitor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (_encreptResponseMonitor.CurrentValue.IsResponseEncreptEnable)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (context.Result is ObjectResult objectResult)
|
|
||||||
{
|
|
||||||
var statusCode = objectResult.StatusCode ?? context.HttpContext.Response.StatusCode;
|
|
||||||
|
|
||||||
var objectValue = objectResult.Value;
|
|
||||||
|
|
||||||
|
|
||||||
if (objectValue is IResponseOutput)
|
|
||||||
{
|
|
||||||
var responseOutput = objectValue as IResponseOutput<object>;
|
|
||||||
|
|
||||||
var path = context.HttpContext?.Request.Path.Value?.ToLower();
|
|
||||||
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(path) && path.Length > 5 && _encreptResponseMonitor.CurrentValue.ApiPathList.Contains(path.ToLower()))
|
|
||||||
{
|
|
||||||
|
|
||||||
if (responseOutput.IsSuccess)
|
|
||||||
{
|
|
||||||
responseOutput.Code = ApiResponseCodeEnum.ResultEncrepted;
|
|
||||||
responseOutput.Data = JsonConvert.SerializeObject(Convert.ToBase64String(Encoding.UTF8.GetBytes(responseOutput.Data.ToString())));
|
|
||||||
|
|
||||||
objectResult.Value = responseOutput;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await next.Invoke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
using IRaCIS.Core.Domain.Share;
|
|
||||||
using IRaCIS.Core.Infrastructure.Encryption;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.BusinessFilter;
|
|
||||||
|
|
||||||
public class EncryptionRequestMiddleware
|
|
||||||
{
|
|
||||||
private readonly RequestDelegate _next;
|
|
||||||
|
|
||||||
private readonly IRCEncreptOption _IRCEncreptOption;
|
|
||||||
|
|
||||||
public EncryptionRequestMiddleware(RequestDelegate next, IOptionsMonitor<IRCEncreptOption> encreptResponseMonitor)
|
|
||||||
{
|
|
||||||
_next = next;
|
|
||||||
|
|
||||||
_IRCEncreptOption = encreptResponseMonitor.CurrentValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task InvokeAsync(HttpContext context)
|
|
||||||
{
|
|
||||||
//模拟前端已经设置该请求头
|
|
||||||
//context.Request.Headers["X-Encrypted-Key"] = "hW8JuJocBzIPWSHURUnYJMZ0l68g6uP9rEdMho8ioFO8amD6GIH+R6RIX5jVFzOwO+lmgBi+4gaVJGGkWJMTcoDTfzzzT1EmfPV+UhFLE9HWvCkEXmDOLE9xCHrbG8TrR1I9+Qd3cvo9HLmrQ58n13cJsM82FBw+reUgiWeklPCkEWM9br2qc9VkCp6gKzimTldNTWBezV86S6j3qHbZpVZm0atdDtGb+zSC9LLA3+oHQwRLJAAGSOAi8CUiRmIQsygRd824wBndkaH2ImEeRjBMs7PqCeK3KsoDp13yHdj2AE751gsfNzf4SF547UPf72m0F2/rBFgrSNy+Jz0T9w==";
|
|
||||||
|
|
||||||
// 检查请求头中是否包含加密的对称密钥
|
|
||||||
if (context.Request.Headers.ContainsKey("X-Encrypted-Key"))
|
|
||||||
{
|
|
||||||
|
|
||||||
var encryptedSymmetricKeyStr = context.Request.Headers["X-Encrypted-Key"].ToString();
|
|
||||||
|
|
||||||
var pemSecretKey = Encoding.UTF8.GetString(Convert.FromBase64String(_IRCEncreptOption.Base64RSAPrivateKey));
|
|
||||||
|
|
||||||
// 使用私钥解密对称密钥
|
|
||||||
var decryptedSymmetricKey = RSAEncryption.Decrypt(pemSecretKey, encryptedSymmetricKeyStr);
|
|
||||||
|
|
||||||
|
|
||||||
#region 处理路径传递参数
|
|
||||||
|
|
||||||
// 处理路径参数解密
|
|
||||||
var path = context.Request.Path.Value;
|
|
||||||
|
|
||||||
// 假设加密的参数在路径中,按照顺序解密路径中的每个部分
|
|
||||||
var pathSegments = path.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
for (int i = 2; i < pathSegments.Length; i++)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(pathSegments[i]))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var decryptedSegment = AesEncryption.Decrypt(pathSegments[i], decryptedSymmetricKey);
|
|
||||||
pathSegments[i] = decryptedSegment;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// 如果不能解密该部分,保持原值
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将解密后的路径重新拼接并设置到请求的Path
|
|
||||||
context.Request.Path = "/" + string.Join("/", pathSegments);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 处理url 传递参数
|
|
||||||
|
|
||||||
// 处理 URL 查询参数的解密
|
|
||||||
var queryParams = context.Request.Query.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ToString());
|
|
||||||
var decryptedQueryParams = new Dictionary<string, string>();
|
|
||||||
|
|
||||||
foreach (var param in queryParams)
|
|
||||||
{
|
|
||||||
var encryptedValue = param.Value;
|
|
||||||
var decryptedValue = AesEncryption.Decrypt(encryptedValue, decryptedSymmetricKey);
|
|
||||||
decryptedQueryParams[param.Key] = decryptedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构造解密后的查询字符串
|
|
||||||
var decryptedQueryString = new QueryString("?" + string.Join("&", decryptedQueryParams.Select(kvp => $"{kvp.Key}={kvp.Value}")));
|
|
||||||
context.Request.QueryString = decryptedQueryString;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 处理body传参
|
|
||||||
|
|
||||||
// 读取并解密请求体中的JSON数据
|
|
||||||
context.Request.EnableBuffering();
|
|
||||||
using (var reader = new StreamReader(context.Request.Body, Encoding.UTF8, leaveOpen: true))
|
|
||||||
{
|
|
||||||
var encryptedBody = await reader.ReadToEndAsync();
|
|
||||||
context.Request.Body.Position = 0;
|
|
||||||
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(encryptedBody))
|
|
||||||
{
|
|
||||||
// 尝试解析为JObject
|
|
||||||
var encryptedJson = JObject.Parse(encryptedBody);
|
|
||||||
var decryptedJson = new JObject();
|
|
||||||
|
|
||||||
// 解密每个字段的值
|
|
||||||
foreach (var property in encryptedJson.Properties())
|
|
||||||
{
|
|
||||||
var encryptedValue = property.Value.ToString();
|
|
||||||
var decryptedValue = AesEncryption.Decrypt(encryptedValue, decryptedSymmetricKey);
|
|
||||||
decryptedJson[property.Name] = decryptedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将解密后的JSON对象转换回字符串,并替换原始请求体
|
|
||||||
var decryptedBody = decryptedJson.ToString();
|
|
||||||
var bodyStream = new MemoryStream(Encoding.UTF8.GetBytes(decryptedBody));
|
|
||||||
context.Request.Body = bodyStream;
|
|
||||||
context.Request.ContentLength = bodyStream.Length;
|
|
||||||
bodyStream.Seek(0, SeekOrigin.Begin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
// 调用下一个中间件
|
|
||||||
await _next(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
using IRaCIS.Core.Application.Helper;
|
using EasyCaching.Core;
|
||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using ZiggyCreatures.Caching.Fusion;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Filter;
|
namespace IRaCIS.Core.Application.Filter;
|
||||||
|
|
||||||
@@ -17,15 +18,15 @@ public class LimitUserRequestAuthorization : IAsyncAuthorizationFilter
|
|||||||
{
|
{
|
||||||
public IStringLocalizer _localizer { get; set; }
|
public IStringLocalizer _localizer { get; set; }
|
||||||
|
|
||||||
private readonly IFusionCache _fusionCache;
|
private readonly IEasyCachingProvider _provider;
|
||||||
|
|
||||||
private readonly IUserInfo _userInfo;
|
private readonly IUserInfo _userInfo;
|
||||||
|
|
||||||
private readonly IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig;
|
private readonly IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig;
|
||||||
|
|
||||||
public LimitUserRequestAuthorization(IFusionCache fusionCache, IUserInfo userInfo, IStringLocalizer localizer, IOptionsMonitor<ServiceVerifyConfigOption> verifyConfig)
|
public LimitUserRequestAuthorization(IEasyCachingProvider provider, IUserInfo userInfo, IStringLocalizer localizer ,IOptionsMonitor<ServiceVerifyConfigOption> verifyConfig)
|
||||||
{
|
{
|
||||||
_fusionCache = fusionCache;
|
_provider = provider;
|
||||||
_userInfo = userInfo;
|
_userInfo = userInfo;
|
||||||
_verifyConfig = verifyConfig;
|
_verifyConfig = verifyConfig;
|
||||||
_localizer = localizer;
|
_localizer = localizer;
|
||||||
@@ -62,7 +63,7 @@ public class LimitUserRequestAuthorization : IAsyncAuthorizationFilter
|
|||||||
|
|
||||||
|
|
||||||
//2、在这里取缓存 进行比较 看是否有其他人进行了登陆,如果其他人登陆了,就把之前用户挤掉
|
//2、在这里取缓存 进行比较 看是否有其他人进行了登陆,如果其他人登陆了,就把之前用户挤掉
|
||||||
var cacheUserToken = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserToken(_userInfo.Id));
|
var cacheUserToken = (await _provider.GetAsync<string>(_userInfo.Id.ToString())).Value;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -72,17 +73,17 @@ public class LimitUserRequestAuthorization : IAsyncAuthorizationFilter
|
|||||||
cacheUserToken = _userInfo.UserToken;
|
cacheUserToken = _userInfo.UserToken;
|
||||||
|
|
||||||
//设置当前用户最新Token
|
//设置当前用户最新Token
|
||||||
await _fusionCache.SetAsync(CacheKeys.UserToken(_userInfo.Id), _userInfo.UserToken, TimeSpan.FromDays(7));
|
await _provider.SetAsync(_userInfo.Id.ToString(), _userInfo.UserToken, TimeSpan.FromDays(7));
|
||||||
|
|
||||||
//重启应用程序,所有人续期,不一下子踢出所有人
|
//重启应用程序,所有人续期,不一下子踢出所有人
|
||||||
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.Id), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
|
await _provider.SetAsync($"{_userInfo.Id.ToString()}_Online", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
|
||||||
|
|
||||||
}
|
}
|
||||||
//是同一个人
|
//是同一个人
|
||||||
else if (cacheUserToken == _userInfo.UserToken)
|
else if (cacheUserToken == _userInfo.UserToken)
|
||||||
{
|
{
|
||||||
|
|
||||||
var cacheTime = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.UserAutoLoginOut(_userInfo.Id));
|
var cacheTime = (await _provider.GetAsync<string>($"{_userInfo.Id.ToString()}_Online")).Value;
|
||||||
|
|
||||||
//过期了 需要自动退出
|
//过期了 需要自动退出
|
||||||
if (string.IsNullOrEmpty(cacheTime))
|
if (string.IsNullOrEmpty(cacheTime))
|
||||||
@@ -91,22 +92,32 @@ public class LimitUserRequestAuthorization : IAsyncAuthorizationFilter
|
|||||||
context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
|
context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||||
|
|
||||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["LimitUser_AccountAuto_LoginOut"], ApiResponseCodeEnum.AutoLoginOut));
|
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["LimitUser_AccountAuto_LoginOut"], ApiResponseCodeEnum.AutoLoginOut));
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(_userInfo.Id), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
|
await _provider.SetAsync($"{_userInfo.Id.ToString()}_Online", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(minutes));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
context.HttpContext.Response.ContentType = "application/json";
|
context.HttpContext.Response.ContentType = "application/json";
|
||||||
context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
|
context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||||
//---您的账户在其他地方已登陆,您被迫下线。
|
//---您的账户在其他地方已登陆,您被迫下线。
|
||||||
|
|
||||||
|
|
||||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["LimitUser_AccountLoggedInElsewhere"], ApiResponseCodeEnum.LoginInOtherPlace));
|
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["LimitUser_AccountLoggedInElsewhere"], ApiResponseCodeEnum.LoginInOtherPlace));
|
||||||
|
|
||||||
|
|
||||||
|
//await context.HttpContext.Response.WriteAsync(JsonConvert.SerializeObject(ResponseOutput.NotOk(_localizer["LimitUser_AccountLoggedInElsewhere"], ApiResponseCodeEnum.LoginInOtherPlace)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,3 +125,52 @@ public class LimitUserRequestAuthorization : IAsyncAuthorizationFilter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//public class UserTypeRequirement : IAuthorizationRequirement
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
|
||||||
|
//public class UserTypeHandler : AuthorizationHandler<UserTypeRequirement>
|
||||||
|
//{
|
||||||
|
|
||||||
|
// private IUserInfo _userInfo;
|
||||||
|
|
||||||
|
// public UserTypeHandler(IUserInfo userInfo)
|
||||||
|
// {
|
||||||
|
// _userInfo = userInfo;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, UserTypeRequirement requirement)
|
||||||
|
// {
|
||||||
|
|
||||||
|
// //if (context.User.Claims.Count() == 0)
|
||||||
|
// //{
|
||||||
|
// // return Task.CompletedTask;
|
||||||
|
// //}
|
||||||
|
|
||||||
|
// //string userId = context.User.Claims.First(c => c.Type == "Userid").Value;
|
||||||
|
// //string qq = context.User.Claims.First(c => c.Type == "QQ").Value;
|
||||||
|
|
||||||
|
// //if (_UserService.Validata(userId, qq))
|
||||||
|
// //{
|
||||||
|
// // context.Succeed(requirement); //验证通过了
|
||||||
|
// //}
|
||||||
|
// ////在这里就可以做验证
|
||||||
|
|
||||||
|
// return Task.CompletedTask;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Filter;
|
namespace IRaCIS.Core.Application.Filter
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class ModelActionFilter : ActionFilterAttribute, IActionFilter
|
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public class ModelActionFilter : ActionFilterAttribute, IActionFilter
|
||||||
|
{
|
||||||
public IStringLocalizer _localizer;
|
public IStringLocalizer _localizer;
|
||||||
public ModelActionFilter(IStringLocalizer localizer)
|
public ModelActionFilter(IStringLocalizer localizer)
|
||||||
{
|
{
|
||||||
@@ -28,7 +29,9 @@ public class ModelActionFilter : ActionFilterAttribute, IActionFilter
|
|||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
//---提供给接口的参数无效。
|
//---提供给接口的参数无效。
|
||||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["ModelAction_InvalidAPIParameter"] + JsonConvert.SerializeObject(validationErrors)));
|
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["ModelAction_InvalidAPIParameter"] + JsonConvert.SerializeObject( validationErrors)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
|
using System;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Filter;
|
namespace IRaCIS.Core.Application.Filter
|
||||||
|
|
||||||
#region snippet_DisableFormValueModelBindingAttribute
|
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
|
||||||
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
|
|
||||||
{
|
{
|
||||||
|
#region snippet_DisableFormValueModelBindingAttribute
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||||
|
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
|
||||||
|
{
|
||||||
public void OnResourceExecuting(ResourceExecutingContext context)
|
public void OnResourceExecuting(ResourceExecutingContext context)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -22,5 +23,6 @@ public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
|
|||||||
public void OnResourceExecuted(ResourceExecutedContext context)
|
public void OnResourceExecuted(ResourceExecutedContext context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
#endregion
|
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
using IRaCIS.Core.Infrastructure;
|
using IRaCIS.Core.Infrastructure;
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Filter;
|
namespace IRaCIS.Core.Application.Filter
|
||||||
|
|
||||||
public class ProjectExceptionFilter : Attribute, IExceptionFilter
|
|
||||||
{
|
{
|
||||||
|
public class ProjectExceptionFilter : Attribute, IExceptionFilter
|
||||||
|
{
|
||||||
private readonly ILogger<ProjectExceptionFilter> _logger;
|
private readonly ILogger<ProjectExceptionFilter> _logger;
|
||||||
|
|
||||||
public IStringLocalizer _localizer;
|
public IStringLocalizer _localizer;
|
||||||
@@ -44,7 +45,6 @@ public class ProjectExceptionFilter : Attribute, IExceptionFilter
|
|||||||
|
|
||||||
context.Result = new JsonResult(ResponseOutput.NotOk(context.Exception.Message, "", error!.Code, localizedInfo: info));
|
context.Result = new JsonResult(ResponseOutput.NotOk(context.Exception.Message, "", error!.Code, localizedInfo: info));
|
||||||
|
|
||||||
|
|
||||||
//warning 级别记录
|
//warning 级别记录
|
||||||
//_logger.LogWarning($"[{error!.LocalizedKey}]:{StaticData.Log_Locoalize_Dic[error!.LocalizedKey]}");
|
//_logger.LogWarning($"[{error!.LocalizedKey}]:{StaticData.Log_Locoalize_Dic[error!.LocalizedKey]}");
|
||||||
}
|
}
|
||||||
@@ -60,16 +60,12 @@ public class ProjectExceptionFilter : Attribute, IExceptionFilter
|
|||||||
_logger.LogError(context.Exception.InnerException is null ? (context.Exception.Message + context.Exception.StackTrace) : (context.Exception.InnerException?.Message + context.Exception.InnerException?.StackTrace));
|
_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
|
else
|
||||||
{
|
{
|
||||||
//继续
|
//继续
|
||||||
}
|
}
|
||||||
|
context.ExceptionHandled = true;//标记当前异常已经被处理过了
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +1,38 @@
|
|||||||
using IRaCIS.Core.Application.Helper;
|
using EasyCaching.Core;
|
||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using ZiggyCreatures.Caching.Fusion;
|
|
||||||
using static IRaCIS.Core.Domain.Share.StaticData;
|
using static IRaCIS.Core.Domain.Share.StaticData;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Filter;
|
namespace IRaCIS.Core.Application.Filter
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 主要为了 处理项目结束 锁库,不允许操作
|
|
||||||
/// </summary>
|
|
||||||
public class TrialResourceFilter : Attribute, IAsyncResourceFilter
|
|
||||||
{
|
{
|
||||||
private readonly IUserInfo _userInfo;
|
/// <summary>
|
||||||
private readonly IFusionCache _fusionCache;
|
/// 主要为了 处理项目结束 锁库,不允许操作
|
||||||
public IStringLocalizer _localizer;
|
/// </summary>
|
||||||
private readonly IRepository<Trial> _trialRepository;
|
public class TrialResourceFilter : Attribute, IAsyncResourceFilter
|
||||||
private readonly List<string> _trialOptList = new List<string>();
|
|
||||||
|
|
||||||
|
|
||||||
public TrialResourceFilter(IFusionCache fusionCache, IRepository<Trial> trialRepository, IStringLocalizer localizer, IUserInfo userInfo, string trialOpt = null, string trialOpt2 = null, string trialOpt3 = null)
|
|
||||||
{
|
{
|
||||||
_fusionCache = fusionCache;
|
private readonly IEasyCachingProvider _provider;
|
||||||
|
private readonly IUserInfo _userInfo;
|
||||||
|
|
||||||
|
public IStringLocalizer _localizer;
|
||||||
|
private readonly List<string> _trialOptList=new List<string>();
|
||||||
|
|
||||||
|
|
||||||
|
public TrialResourceFilter(IEasyCachingProvider provider, IStringLocalizer localizer , IUserInfo userInfo, string trialOpt = null, string trialOpt2 = null, string trialOpt3 = null)
|
||||||
|
{
|
||||||
|
_provider = provider;
|
||||||
_userInfo = userInfo;
|
_userInfo = userInfo;
|
||||||
_localizer = localizer;
|
_localizer = localizer;
|
||||||
_trialRepository = trialRepository;
|
//_trialOpt = trialOpt;
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(trialOpt)) _trialOptList.Add(trialOpt.Trim());
|
if (!string.IsNullOrWhiteSpace(trialOpt)) _trialOptList.Add(trialOpt.Trim());
|
||||||
if (!string.IsNullOrWhiteSpace(trialOpt2)) _trialOptList.Add(trialOpt2.Trim());
|
if (!string.IsNullOrWhiteSpace(trialOpt2)) _trialOptList.Add(trialOpt2.Trim());
|
||||||
if (!string.IsNullOrWhiteSpace(trialOpt3)) _trialOptList.Add(trialOpt3.Trim());
|
if (!string.IsNullOrWhiteSpace(trialOpt3)) _trialOptList.Add(trialOpt3.Trim());
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//优先选择异步的方法
|
//优先选择异步的方法
|
||||||
@@ -41,21 +41,10 @@ public class TrialResourceFilter : Attribute, IAsyncResourceFilter
|
|||||||
// var typeFilter = context.ActionDescriptor.EndpointMetadata.Where(t => t.GetType() == typeof(TypeFilterAttribute)).Select(t => (TypeFilterAttribute)t).ToList().FirstOrDefault();
|
// var typeFilter = context.ActionDescriptor.EndpointMetadata.Where(t => t.GetType() == typeof(TypeFilterAttribute)).Select(t => (TypeFilterAttribute)t).ToList().FirstOrDefault();
|
||||||
//var _trialOptList= typeFilter.Arguments.Select(t => t.ToString()).ToList();
|
//var _trialOptList= typeFilter.Arguments.Select(t => t.ToString()).ToList();
|
||||||
|
|
||||||
// 获取当前请求的 Host 信息
|
|
||||||
var requestHost = context.HttpContext.Request.Host;
|
|
||||||
|
|
||||||
// 检查请求是否来自 localhost:6100
|
|
||||||
if (requestHost.Host == "localhost" && (requestHost.Port == 6100|| requestHost.Port==3305))
|
|
||||||
{
|
|
||||||
await next.Invoke();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region 处理新的用户类型,不能操作项目相关接口
|
#region 处理新的用户类型,不能操作项目相关接口
|
||||||
|
|
||||||
// 后期列举出具体的类型,其他任何用户类型,都不允许操作
|
// 后期列举出具体的类型,其他任何用户类型,都不允许操作
|
||||||
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA && _userInfo.RequestUrl.ToLower() != "TrialDocument/userConfirm".ToLower())
|
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA && _userInfo.RequestUrl.ToLower()!= "TrialDocument/userConfirm".ToLower())
|
||||||
{
|
{
|
||||||
//---对不起,您的账户没有操作权限。
|
//---对不起,您的账户没有操作权限。
|
||||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_NoAccessPermission"]));
|
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_NoAccessPermission"]));
|
||||||
@@ -127,26 +116,21 @@ public class TrialResourceFilter : Attribute, IAsyncResourceFilter
|
|||||||
if (matchResult.Success)
|
if (matchResult.Success)
|
||||||
{
|
{
|
||||||
//有可能匹配错误 "trialId":"","documentId":"b8180000-3e2c-0016-9fe0-08da33f96236" 从缓存里面验证下
|
//有可能匹配错误 "trialId":"","documentId":"b8180000-3e2c-0016-9fe0-08da33f96236" 从缓存里面验证下
|
||||||
|
var cacheResultDic = _provider.GetAll<string>(new[] { matchResult.Value });
|
||||||
|
|
||||||
trialIdStr = matchResult.Value;
|
var trialStatusStr = cacheResultDic[matchResult.Value.ToLower()].Value;
|
||||||
|
|
||||||
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
if (!string.IsNullOrWhiteSpace(trialStatusStr))
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(trialStatusStr))
|
|
||||||
{
|
{
|
||||||
|
trialIdStr = matchResult.Value;
|
||||||
//数据库 检查该项目Id不对
|
|
||||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_ReferTrialIdFailed"]));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//---正则取请求Refer 中trialId 失败,请联系开发人员核查
|
//---正则取请求Refer 中trialId 失败,请联系开发人员核查
|
||||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_ReferTrialIdFailed"]));
|
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["TrialResource_ReferTrialIdFailed"]));
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//使用字符串取 如果是swagger 可能有时取的不对 因为空格的原因
|
//使用字符串取 如果是swagger 可能有时取的不对 因为空格的原因
|
||||||
@@ -157,12 +141,34 @@ public class TrialResourceFilter : Attribute, IAsyncResourceFilter
|
|||||||
}
|
}
|
||||||
|
|
||||||
//通过path 或者body 找到trialId 了
|
//通过path 或者body 找到trialId 了
|
||||||
if (!string.IsNullOrWhiteSpace(trialIdStr))
|
if ( !string.IsNullOrWhiteSpace(trialIdStr))
|
||||||
{
|
{
|
||||||
var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));
|
|
||||||
|
//如果没缓存数据,可能定时任务没执行或者缓存丢失 在此重新缓存
|
||||||
|
if (_provider.GetCount() == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
var _trialRepository = context.HttpContext.RequestServices.GetService(typeof(IRepository<Trial>)) as IRepository<Trial>;
|
||||||
|
|
||||||
|
var list = _trialRepository.IfNullThrowException().Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr })
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7)));
|
||||||
|
}
|
||||||
|
|
||||||
|
var cacheResultDic = _provider.GetAll<string>(new[] { trialIdStr });
|
||||||
|
|
||||||
|
var trialStatusStr = cacheResultDic[trialIdStr].Value;
|
||||||
|
|
||||||
|
//意外 导致缓存过期,调整服务器时间,测试不想重启程序
|
||||||
|
if (string.IsNullOrWhiteSpace(trialStatusStr))
|
||||||
|
{
|
||||||
|
var trialRepository = context.HttpContext.RequestServices.GetService(typeof(IRepository<Trial>)) as IRepository<Trial>;
|
||||||
|
trialStatusStr = trialRepository?.Where(t => t.Id == Guid.Parse(trialIdStr)).Select(t => t.TrialStatusStr).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方,比如项目配置(有的在多种状态(初始化,ongoing)都可以操作,有的仅仅在Initializing)还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
|
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方,比如项目配置(有的在多种状态(初始化,ongoing)都可以操作,有的仅仅在Initializing)还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
|
||||||
if (trialStatusStr == StaticData.TrialState.TrialOngoing || _trialOptList.Any(t => t == TrialOpt.BeforeOngoingCantOpt))
|
if (trialStatusStr == StaticData.TrialState.TrialOngoing || _trialOptList.Any(t=>t== TrialOpt.BeforeOngoingCantOpt) )
|
||||||
{
|
{
|
||||||
|
|
||||||
await next.Invoke();
|
await next.Invoke();
|
||||||
@@ -178,7 +184,7 @@ public class TrialResourceFilter : Attribute, IAsyncResourceFilter
|
|||||||
|
|
||||||
}
|
}
|
||||||
//添加项目 签名系统文档的时候 不做拦截 但是更新项目 签名项目文档的时候需要拦截
|
//添加项目 签名系统文档的时候 不做拦截 但是更新项目 签名项目文档的时候需要拦截
|
||||||
else if (_trialOptList.Any(t => t == TrialOpt.AddOrUpdateTrial || t == TrialOpt.SignSystemDocNoTrialId))
|
else if (_trialOptList.Any(t => t == TrialOpt.AddOrUpdateTrial ||t ==TrialOpt.SignSystemDocNoTrialId))
|
||||||
{
|
{
|
||||||
await next.Invoke();
|
await next.Invoke();
|
||||||
}
|
}
|
||||||
@@ -192,5 +198,6 @@ public class TrialResourceFilter : Attribute, IAsyncResourceFilter
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
using IRaCIS.Core.Domain.Share;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using IRaCIS.Core.Domain.Share;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Service.BusinessFilter;
|
namespace IRaCIS.Application.Services.BusinessFilter
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 统一返回前端数据包装,之前在控制器包装,现在修改为动态Api 在ResultFilter这里包装,减少重复冗余代码
|
|
||||||
/// by zhouhang 2021.09.12 周末
|
|
||||||
/// </summary>
|
|
||||||
public class UnifiedApiResultFilter : Attribute, IAsyncResultFilter
|
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 统一返回前端数据包装,之前在控制器包装,现在修改为动态Api 在ResultFilter这里包装,减少重复冗余代码
|
||||||
|
/// by zhouhang 2021.09.12 周末
|
||||||
|
/// </summary>
|
||||||
|
public class UnifiedApiResultFilter : Attribute, IAsyncResultFilter
|
||||||
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public UnifiedApiResultFilter(ILogger<UnifiedApiResultFilter> logger)
|
public UnifiedApiResultFilter(ILogger<UnifiedApiResultFilter> logger)
|
||||||
@@ -119,4 +119,5 @@ public class UnifiedApiResultFilter : Attribute, IAsyncResultFilter
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,164 +0,0 @@
|
|||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Configuration.Json;
|
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.Domain.Share;
|
|
||||||
|
|
||||||
[Description("多环境 配置环境实体")]
|
|
||||||
public class ServiceVerifyConfigOption
|
|
||||||
{
|
|
||||||
public bool OpenUserComplexPassword { get; set; }
|
|
||||||
|
|
||||||
public bool OpenSignDocumentBeforeWork { get; set; }
|
|
||||||
|
|
||||||
public bool OpenTrialRelationDelete { get; set; }
|
|
||||||
|
|
||||||
public bool OpenLoginLimit { get; set; }
|
|
||||||
|
|
||||||
public int LoginMaxFailCount { get; set; }
|
|
||||||
|
|
||||||
public int LoginFailLockMinutes { get; set; }
|
|
||||||
|
|
||||||
public int AutoLoginOutMinutes { get; set; }
|
|
||||||
|
|
||||||
public bool OpenLoginMFA { get; set; }
|
|
||||||
|
|
||||||
[Description("连续阅片时间 (min)")]
|
|
||||||
public int ContinuousReadingTimeMin { get; set; }
|
|
||||||
|
|
||||||
[Description("休息时间 (min)")]
|
|
||||||
public int ReadingRestTimeMin { get; set; }
|
|
||||||
[Description("是否需要修改密码")]
|
|
||||||
public bool IsNeedChangePassWord { get; set; }
|
|
||||||
|
|
||||||
[Description("修改密码的天数")]
|
|
||||||
public int ChangePassWordDays { get; set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SystemEmailSendConfig
|
|
||||||
{
|
|
||||||
public int Port { get; set; }
|
|
||||||
|
|
||||||
public string Host { get; set; } = string.Empty;
|
|
||||||
public string FromEmail { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string FromName { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string AuthorizationCode { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string SiteUrl { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string OrganizationName { get; set; } = string.Empty;
|
|
||||||
public string OrganizationNameCN { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string CompanyName { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string CompanyNameCN { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string CompanyShortName { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string CompanyShortNameCN { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public bool IsEnv_US { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SystemEmailSendConfigView
|
|
||||||
{
|
|
||||||
public string CompanyName { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string CompanyNameCN { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string CompanyShortName { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string CompanyShortNameCN { get; set; } = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SystemPacsConfig
|
|
||||||
{
|
|
||||||
public int Port { get; set; }
|
|
||||||
|
|
||||||
public string IP { get; set; } = string.Empty;
|
|
||||||
}
|
|
||||||
public class IRCEncreptOption
|
|
||||||
{
|
|
||||||
public string Base64RSAPublicKey { get; set; }
|
|
||||||
|
|
||||||
public string Base64RSAPrivateKey { get; set; }
|
|
||||||
public bool IsResponseEncreptEnable { get; set; }
|
|
||||||
|
|
||||||
public List<string> ApiPathList { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class IRaCISBasicConfigOption
|
|
||||||
{
|
|
||||||
public string DoctorCodePrefix { get; set; }
|
|
||||||
public string UserCodePrefix { get; set; }
|
|
||||||
public string QCChallengeCodePrefix { get; set; }
|
|
||||||
public string DicomStudyCodePrefix { get; set; }
|
|
||||||
public string TaskStudyCodePrefix { get; set; }
|
|
||||||
public string NoneDicomStudyCodePrefix { get; set; }
|
|
||||||
public int ImageShareExpireDays { get; set; }
|
|
||||||
public string SystemSiteCodePrefix { get; set; }
|
|
||||||
public string BlindTaskPrefix { get; set; }
|
|
||||||
public string DefaultPassword { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[Description("项目基础配置规则")]
|
|
||||||
public static class AppSettings
|
|
||||||
{
|
|
||||||
|
|
||||||
public static IRaCISBasicConfigOption IRaCISBasicConfig { get; set; }
|
|
||||||
|
|
||||||
static AppSettings()
|
|
||||||
{
|
|
||||||
var configuration = new ConfigurationBuilder()
|
|
||||||
.Add(new JsonConfigurationSource
|
|
||||||
{
|
|
||||||
Path = "appsettings.json",
|
|
||||||
ReloadOnChange = true
|
|
||||||
})
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
// 手动绑定配置
|
|
||||||
var appSettings = new IRaCISBasicConfigOption();
|
|
||||||
configuration.GetSection("IRaCISBasicConfig").Bind(appSettings);
|
|
||||||
|
|
||||||
IRaCISBasicConfig = appSettings;
|
|
||||||
}
|
|
||||||
//获取实体编码字符串
|
|
||||||
public static string GetCodeStr(int codeInt, string typeStr)
|
|
||||||
{
|
|
||||||
switch (typeStr)
|
|
||||||
{
|
|
||||||
case nameof(Doctor):
|
|
||||||
return IRaCISBasicConfig.DoctorCodePrefix + codeInt.ToString("D4");
|
|
||||||
|
|
||||||
case nameof(User):
|
|
||||||
return IRaCISBasicConfig.UserCodePrefix + codeInt.ToString("D4");
|
|
||||||
|
|
||||||
case nameof(QCChallenge):
|
|
||||||
return IRaCISBasicConfig.QCChallengeCodePrefix + codeInt.ToString("D5");
|
|
||||||
|
|
||||||
case nameof(NoneDicomStudy):
|
|
||||||
return IRaCISBasicConfig.NoneDicomStudyCodePrefix + codeInt.ToString("D5");
|
|
||||||
|
|
||||||
case nameof(DicomStudy):
|
|
||||||
return IRaCISBasicConfig.DicomStudyCodePrefix + codeInt.ToString("D5");
|
|
||||||
|
|
||||||
case nameof(TaskStudy):
|
|
||||||
return IRaCISBasicConfig.TaskStudyCodePrefix + codeInt.ToString("D5");
|
|
||||||
|
|
||||||
case nameof(VisitTask):
|
|
||||||
return "W" + codeInt.ToString("D5");
|
|
||||||
|
|
||||||
case nameof(Site):
|
|
||||||
return IRaCISBasicConfig.SystemSiteCodePrefix + codeInt.ToString("D4");
|
|
||||||
|
|
||||||
default:
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
global using AutoMapper.QueryableExtensions;
|
|
||||||
global using IRaCIS.Core.Application.Service;
|
|
||||||
global using IRaCIS.Core.Domain.Models;
|
|
||||||
global using IRaCIS.Core.Infra.EFCore;
|
|
||||||
global using IRaCIS.Core.Infrastructure.Extention;
|
|
||||||
global using Microsoft.EntityFrameworkCore;
|
|
||||||
global using System.Linq.Expressions;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,4 +1,9 @@
|
|||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Helper
|
namespace IRaCIS.Core.Application.Helper
|
||||||
{
|
{
|
||||||
@@ -14,9 +19,9 @@ namespace IRaCIS.Core.Application.Helper
|
|||||||
|
|
||||||
|
|
||||||
//是否翻译依赖其他属性
|
//是否翻译依赖其他属性
|
||||||
public bool IsTranslateDenpendOtherProperty => !string.IsNullOrWhiteSpace(DependPropertyName);
|
public bool IsTranslateDenpendOtherProperty =>!string.IsNullOrWhiteSpace(DependPropertyName);
|
||||||
|
|
||||||
public string DependPropertyName { get; set; } = string.Empty;
|
public string DependPropertyName { get; set; }=string.Empty;
|
||||||
|
|
||||||
public string DependPropertyValueStr { get; set; } = string.Empty;
|
public string DependPropertyValueStr { get; set; } = string.Empty;
|
||||||
|
|
||||||
@@ -28,7 +33,7 @@ namespace IRaCIS.Core.Application.Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
//针对不同的标准 翻译的字典不一样
|
//针对不同的标准 翻译的字典不一样
|
||||||
public DictionaryTranslateAttribute(string dicParentCode, CriterionType criterionType)
|
public DictionaryTranslateAttribute(string dicParentCode, CriterionType criterionType )
|
||||||
{
|
{
|
||||||
DicParentCode = dicParentCode;
|
DicParentCode = dicParentCode;
|
||||||
|
|
||||||
@@ -37,7 +42,7 @@ namespace IRaCIS.Core.Application.Helper
|
|||||||
|
|
||||||
//针对业务某个属性的值 不一样 用的翻译字典不一样
|
//针对业务某个属性的值 不一样 用的翻译字典不一样
|
||||||
|
|
||||||
public DictionaryTranslateAttribute(string dicParentCode, string dependPropertyName, string dependPropertyValueStr)
|
public DictionaryTranslateAttribute(string dicParentCode,string dependPropertyName, string dependPropertyValueStr)
|
||||||
{
|
{
|
||||||
DicParentCode = dicParentCode;
|
DicParentCode = dicParentCode;
|
||||||
|
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
namespace IRaCIS.Core.Application.Helper;
|
|
||||||
|
|
||||||
|
|
||||||
public static class CacheKeys
|
|
||||||
{
|
|
||||||
//项目缓存
|
|
||||||
public static string Trial(string trialIdStr) => $"TrialId:{trialIdStr}";
|
|
||||||
|
|
||||||
//检查编号递增锁
|
|
||||||
public static string TrialStudyMaxCode(Guid trialId) => $"TrialStudyMaxCode:{trialId}";
|
|
||||||
|
|
||||||
public static string TrialStudyUidUploading(Guid trialId, string studyUid) => $"TrialStudyUid:{trialId}_{studyUid}";
|
|
||||||
//CRC上传影像提交锁key
|
|
||||||
public static string TrialStudyUidDBLock(Guid trialId, string studyUid) => $"TrialStudyUidDBLock:{trialId}_{studyUid}";
|
|
||||||
|
|
||||||
public static string TrialTaskStudyUidUploading(Guid trialId, Guid visiTaskId, string studyUid) => $"TrialStudyUid:{trialId}_{visiTaskId}_{studyUid}";
|
|
||||||
//影像后处理上传提交锁key
|
|
||||||
public static string TrialTaskStudyUidDBLock(Guid trialId, Guid visiTaskId, string studyUid) => $"TrialTaskStudyUidDBLock:{trialId}_{visiTaskId}_{studyUid}";
|
|
||||||
//系统匿名化
|
|
||||||
public static string SystemAnonymization => $"SystemAnonymization";
|
|
||||||
//前端国际化
|
|
||||||
public static string FrontInternational => $"FrontInternationalList";
|
|
||||||
|
|
||||||
//登录挤账号
|
|
||||||
public static string UserToken(Guid userId) => $"UserToken:{userId}";
|
|
||||||
|
|
||||||
//超时没请求接口自动退出
|
|
||||||
public static string UserAutoLoginOut(Guid userId) => $"UserAutoLoginOut:{userId}";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 跳过阅片
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="userId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string SkipReadingCacheKey(Guid userId) => $"{userId}SkipReadingCache";
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 开始阅片时间
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="userId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string StartReadingTimeKey(Guid userId) => $"{userId}StartReadingTime";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 开始休息时间
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="userId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string StartRestTime(Guid userId) => $"{userId}StartRestTime";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class CacheHelper
|
|
||||||
{
|
|
||||||
public static async Task<string?> GetTrialStatusAsync(Guid trialId, IRepository<Trial> _trialRepository)
|
|
||||||
{
|
|
||||||
var statusStr = await _trialRepository.Where(t => t.Id == trialId, ignoreQueryFilters: true).Select(t => t.TrialStatusStr).FirstOrDefaultAsync();
|
|
||||||
|
|
||||||
return statusStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<List<SystemAnonymization>> GetSystemAnonymizationListAsync(IRepository<SystemAnonymization> _systemAnonymizationRepository)
|
|
||||||
{
|
|
||||||
var list = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync();
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using NPOI.SS.Formula.Functions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Helper
|
||||||
|
{
|
||||||
|
public static class EmailMaskHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
//显示位数:3分之2的位数,向上取整
|
||||||
|
//取哪几个个值:最后一位和前面几位
|
||||||
|
//其他:3个***。
|
||||||
|
//比如:hlj23@126.com
|
||||||
|
//为:hlj***3@126.com
|
||||||
|
|
||||||
|
//he@126.com
|
||||||
|
//为:h*** e@126.com
|
||||||
|
|
||||||
|
public static string MaskEmail(string email)
|
||||||
|
{
|
||||||
|
|
||||||
|
// 找到 "@" 符号的位置
|
||||||
|
int atIndex = email.IndexOf('@');
|
||||||
|
|
||||||
|
string visiblePartBefore = email.Substring(0, atIndex);
|
||||||
|
|
||||||
|
string afterAt = email.Substring(atIndex + 1);
|
||||||
|
|
||||||
|
int visibleLength = (int)Math.Ceiling((double)visiblePartBefore.Length * 2 / 3);
|
||||||
|
|
||||||
|
// 替换中间两位字符为星号
|
||||||
|
string hiddenPartBeforeAt = visiblePartBefore.Substring(0, visibleLength - 1) + "***" + visiblePartBefore.Last();
|
||||||
|
|
||||||
|
|
||||||
|
// 组合隐藏和可见部分
|
||||||
|
string hiddenEmail = hiddenPartBeforeAt + "@" + afterAt;
|
||||||
|
|
||||||
|
return hiddenEmail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,46 +1,41 @@
|
|||||||
using IRaCIS.Application.Contracts;
|
using DocumentFormat.OpenXml.Drawing.Diagrams;
|
||||||
|
using DocumentFormat.OpenXml.Spreadsheet;
|
||||||
|
using DocumentFormat.OpenXml.Wordprocessing;
|
||||||
|
using IRaCIS.Application.Contracts;
|
||||||
using IRaCIS.Application.Interfaces;
|
using IRaCIS.Application.Interfaces;
|
||||||
using IRaCIS.Core.API._ServiceExtensions.NewtonsoftJson;
|
|
||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Core.Application.Helper;
|
||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using MiniExcelLibs;
|
using MiniExcelLibs;
|
||||||
using MiniExcelLibs.OpenXml;
|
using MiniExcelLibs.OpenXml;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
using NPOI.HSSF.UserModel;
|
using NPOI.HSSF.UserModel;
|
||||||
using NPOI.SS.Formula.Functions;
|
|
||||||
using NPOI.SS.UserModel;
|
|
||||||
using NPOI.XSSF.UserModel;
|
using NPOI.XSSF.UserModel;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Globalization;
|
using System.IO;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Service;
|
namespace IRaCIS.Core.Application.Service;
|
||||||
|
|
||||||
public static class ExcelExportHelper
|
public static class ExcelExportHelper
|
||||||
{
|
{
|
||||||
//MiniExcel_Export
|
//MiniExcel_Export
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="code"></param>
|
|
||||||
/// <param name="data"></param>
|
|
||||||
/// <param name="exportFileNamePrefix">文件名前缀</param>
|
|
||||||
/// <param name="_commonDocumentRepository"></param>
|
|
||||||
/// <param name="_hostEnvironment"></param>
|
|
||||||
/// <param name="_dictionaryService"></param>
|
|
||||||
/// <param name="translateType"></param>
|
|
||||||
/// <param name="criterionType"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task<IActionResult> DataExportAsync(string code, ExcelExportInfo data, string exportFileNamePrefix, IRepository<CommonDocument> _commonDocumentRepository, IWebHostEnvironment _hostEnvironment, IDictionaryService? _dictionaryService = null, Type? translateType = null, CriterionType? criterionType = null)
|
public static async Task<IActionResult> DataExportAsync(string code, ExcelExportInfo data, string exportFileNamePrefix, IRepository<CommonDocument> _commonDocumentRepository, IWebHostEnvironment _hostEnvironment, IDictionaryService? _dictionaryService = null, Type? translateType = null, CriterionType? criterionType = null)
|
||||||
{
|
{
|
||||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
|
||||||
|
|
||||||
//判断是否有字典翻译
|
//判断是否有字典翻译
|
||||||
|
|
||||||
object translateData = data;
|
object translateData = data;
|
||||||
|
|
||||||
if (_dictionaryService != null && translateType != null)
|
if (_dictionaryService != null && translateType != null)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
////只标注单个的时候
|
||||||
|
//var needTranslatePropertyList = translateType.GetProperties().Where(t => t.IsDefined(typeof(DictionaryTranslateAttribute), true))
|
||||||
|
// .Select(c => new { c.Name, DicParentCode = ((DictionaryTranslateAttribute?)c.GetCustomAttributes(typeof(DictionaryTranslateAttribute), false)[0])?.DicParentCode }).ToList();
|
||||||
|
|
||||||
|
|
||||||
//一个值 对应不同的字典翻译
|
//一个值 对应不同的字典翻译
|
||||||
var needTranslatePropertyList = translateType.GetProperties().Where(t => t.IsDefined(typeof(DictionaryTranslateAttribute), true))
|
var needTranslatePropertyList = translateType.GetProperties().Where(t => t.IsDefined(typeof(DictionaryTranslateAttribute), true))
|
||||||
.SelectMany(c =>
|
.SelectMany(c =>
|
||||||
@@ -67,18 +62,12 @@ public static class ExcelExportHelper
|
|||||||
var newObjList = new List<object>();
|
var newObjList = new List<object>();
|
||||||
var no = 1;
|
var no = 1;
|
||||||
|
|
||||||
foreach (var item in dic[key] as IList)
|
foreach (var item in dic[key] as IList )
|
||||||
{
|
{
|
||||||
|
//var itemDic = JsonConvert.DeserializeObject<IDictionary<string, object>>(item.ToJsonNotIgnoreNull());
|
||||||
|
|
||||||
var itemDic = item.ConvertToDictionary();
|
var itemDic = item.ConvertToDictionary();
|
||||||
|
|
||||||
//处理集合里面时间类型,根据当前语言将时间转变为字符串
|
|
||||||
foreach (var itemValuePair in itemDic)
|
|
||||||
{
|
|
||||||
if (DateTime.TryParse(itemValuePair.Value?.ToString(), out DateTime result))
|
|
||||||
{
|
|
||||||
itemDic[itemValuePair.Key] = ExportExcelConverterDate.DateTimeInternationalToString(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
foreach (var needTranslateProperty in needTranslatePropertyList)
|
foreach (var needTranslateProperty in needTranslatePropertyList)
|
||||||
@@ -90,7 +79,7 @@ public static class ExcelExportHelper
|
|||||||
{
|
{
|
||||||
var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();
|
var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();
|
||||||
|
|
||||||
itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
|
itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t=>data.IsEn_US?t.Value:t.ValueCN).FirstOrDefault() ?? String.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//普通翻译 或者某一标准翻译
|
//普通翻译 或者某一标准翻译
|
||||||
@@ -99,7 +88,7 @@ public static class ExcelExportHelper
|
|||||||
var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();
|
var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();
|
||||||
|
|
||||||
|
|
||||||
itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
|
itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => data.IsEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -115,7 +104,6 @@ public static class ExcelExportHelper
|
|||||||
dic[key] = newObjList;
|
dic[key] = newObjList;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -151,7 +139,7 @@ public static class ExcelExportHelper
|
|||||||
|
|
||||||
if (sheetCount == 2)
|
if (sheetCount == 2)
|
||||||
{
|
{
|
||||||
if (isEn_US)
|
if (data.IsEn_US)
|
||||||
{
|
{
|
||||||
workbook.RemoveSheetAt(0);
|
workbook.RemoveSheetAt(0);
|
||||||
}
|
}
|
||||||
@@ -161,7 +149,7 @@ public static class ExcelExportHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
var memoryStream2 = new MemoryStream();
|
var memoryStream2 = new MemoryStream();
|
||||||
workbook.Write(memoryStream2, true);
|
workbook.Write(memoryStream2,true);
|
||||||
|
|
||||||
memoryStream2.Seek(0, SeekOrigin.Begin);
|
memoryStream2.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
@@ -172,6 +160,11 @@ public static class ExcelExportHelper
|
|||||||
//fileNmae = workbook.GetSheetName(0);
|
//fileNmae = workbook.GetSheetName(0);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region MiniExcel
|
#region MiniExcel
|
||||||
|
|
||||||
var memoryStream = new MemoryStream();
|
var memoryStream = new MemoryStream();
|
||||||
@@ -188,18 +181,29 @@ public static class ExcelExportHelper
|
|||||||
|
|
||||||
return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||||
{
|
{
|
||||||
FileDownloadName = $"{(string.IsNullOrEmpty(exportFileNamePrefix) ? "" : exportFileNamePrefix + "_")}{Path.GetFileNameWithoutExtension(fileName)}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx"
|
FileDownloadName = $"{(string.IsNullOrEmpty(exportFileNamePrefix) ? "" : exportFileNamePrefix+ "_") }{Path.GetFileNameWithoutExtension(fileName) }_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx"
|
||||||
};
|
};
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Magicodes 模板规则不一样
|
||||||
|
|
||||||
|
////创建Excel导出对象
|
||||||
|
//IExportFileByTemplate exporter = new ExcelExporter();
|
||||||
|
|
||||||
|
////根据模板导出
|
||||||
|
//var result = await exporter.ExportBytesByTemplate(exportInfo, tplPath);
|
||||||
|
|
||||||
|
|
||||||
|
//return new XlsxFileResult(bytes: result, fileDownloadName: $"{doc.Name}_{DateTime.Now.ToString("yyyy-MM-dd:hh:mm:ss")}.xlsx");
|
||||||
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static async Task<(MemoryStream, string)> DataExport_NpoiTestAsync(string code, ExcelExportInfo data, IRepository<CommonDocument> _commonDocumentRepository, IWebHostEnvironment _hostEnvironment, IDictionaryService? _dictionaryService = null, Type? translateType = null, CriterionType? criterionType = null)
|
public static async Task<(MemoryStream, string)> DataExport_NpoiTestAsync(string code, ExcelExportInfo data, IRepository<CommonDocument> _commonDocumentRepository, IWebHostEnvironment _hostEnvironment, IDictionaryService? _dictionaryService = null, Type? translateType = null, CriterionType? criterionType = null)
|
||||||
{
|
{
|
||||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
|
||||||
//判断是否有字典翻译
|
//判断是否有字典翻译
|
||||||
|
|
||||||
object translateData = data;
|
object translateData = data;
|
||||||
@@ -207,6 +211,11 @@ public static class ExcelExportHelper
|
|||||||
if (_dictionaryService != null && translateType != null)
|
if (_dictionaryService != null && translateType != null)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
////只标注单个的时候
|
||||||
|
//var needTranslatePropertyList = translateType.GetProperties().Where(t => t.IsDefined(typeof(DictionaryTranslateAttribute), true))
|
||||||
|
// .Select(c => new { c.Name, DicParentCode = ((DictionaryTranslateAttribute?)c.GetCustomAttributes(typeof(DictionaryTranslateAttribute), false)[0])?.DicParentCode }).ToList();
|
||||||
|
|
||||||
|
|
||||||
//一个值 对应不同的字典翻译
|
//一个值 对应不同的字典翻译
|
||||||
var needTranslatePropertyList = translateType.GetProperties().Where(t => t.IsDefined(typeof(DictionaryTranslateAttribute), true))
|
var needTranslatePropertyList = translateType.GetProperties().Where(t => t.IsDefined(typeof(DictionaryTranslateAttribute), true))
|
||||||
.SelectMany(c =>
|
.SelectMany(c =>
|
||||||
@@ -238,15 +247,6 @@ public static class ExcelExportHelper
|
|||||||
//var itemDic = JsonConvert.DeserializeObject<IDictionary<string, object>>(item.ToJsonNotIgnoreNull());
|
//var itemDic = JsonConvert.DeserializeObject<IDictionary<string, object>>(item.ToJsonNotIgnoreNull());
|
||||||
var itemDic = item.ConvertToDictionary();
|
var itemDic = item.ConvertToDictionary();
|
||||||
|
|
||||||
//处理集合里面时间类型,根据当前语言将时间转变为字符串
|
|
||||||
foreach (var itemValuePair in itemDic)
|
|
||||||
{
|
|
||||||
if (DateTime.TryParse(itemValuePair.Value?.ToString(), out DateTime result))
|
|
||||||
{
|
|
||||||
itemDic[itemValuePair.Key] = ExportExcelConverterDate.DateTimeInternationalToString(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var needTranslateProperty in needTranslatePropertyList)
|
foreach (var needTranslateProperty in needTranslatePropertyList)
|
||||||
{
|
{
|
||||||
//翻译的属性依赖其他属性
|
//翻译的属性依赖其他属性
|
||||||
@@ -256,7 +256,7 @@ public static class ExcelExportHelper
|
|||||||
{
|
{
|
||||||
var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();
|
var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();
|
||||||
|
|
||||||
itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
|
itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => data.IsEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//普通翻译 或者某一标准翻译
|
//普通翻译 或者某一标准翻译
|
||||||
@@ -265,7 +265,7 @@ public static class ExcelExportHelper
|
|||||||
var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();
|
var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();
|
||||||
|
|
||||||
|
|
||||||
itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
|
itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => data.IsEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -310,7 +310,7 @@ public static class ExcelExportHelper
|
|||||||
|
|
||||||
if (sheetCount == 2)
|
if (sheetCount == 2)
|
||||||
{
|
{
|
||||||
if (isEn_US)
|
if (data.IsEn_US)
|
||||||
{
|
{
|
||||||
workbook.RemoveSheetAt(0);
|
workbook.RemoveSheetAt(0);
|
||||||
}
|
}
|
||||||
@@ -320,7 +320,7 @@ public static class ExcelExportHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
var memoryStream2 = new MemoryStream();
|
var memoryStream2 = new MemoryStream();
|
||||||
workbook.Write(memoryStream2, true);
|
workbook.Write(memoryStream2,true);
|
||||||
|
|
||||||
memoryStream2.Seek(0, SeekOrigin.Begin);
|
memoryStream2.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
@@ -355,86 +355,4 @@ public static class ExcelExportHelper
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 导出文件模板
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inDto"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task<FileResult> ExportTemplateAsync(ExportTemplateServiceDto inDto)
|
|
||||||
{
|
|
||||||
var (physicalPath, fileName) = await FileStoreHelper.GetCommonDocPhysicalFilePathAsync(inDto.hostEnvironment, inDto.commonDocumentRepository, inDto.TemplateCode);
|
|
||||||
|
|
||||||
|
|
||||||
//模板路径
|
|
||||||
var tplPath = physicalPath;
|
|
||||||
|
|
||||||
#region 根据中英文 删除模板sheet
|
|
||||||
|
|
||||||
// 打开模板文件
|
|
||||||
var templateFile = new FileStream(tplPath, FileMode.Open, FileAccess.Read);
|
|
||||||
|
|
||||||
// 获取文件流
|
|
||||||
var templateStream = new MemoryStream();
|
|
||||||
templateFile.CopyTo(templateStream);
|
|
||||||
templateStream.Seek(0, SeekOrigin.Begin);
|
|
||||||
|
|
||||||
var workbook = new XSSFWorkbook(templateStream);
|
|
||||||
|
|
||||||
int sheetCount = workbook.NumberOfSheets;
|
|
||||||
|
|
||||||
if (sheetCount == 2)
|
|
||||||
{
|
|
||||||
if (inDto.IsEnglish)
|
|
||||||
{
|
|
||||||
workbook.RemoveSheetAt(0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
workbook.RemoveSheetAt(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
ISheet sheet = workbook.GetSheetAt(0); // 获取第一个工作表
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < sheet.LastRowNum + 1; i++)
|
|
||||||
{
|
|
||||||
IRow row = sheet.GetRow(i);
|
|
||||||
for (int j = 0; j < sheet.LastRowNum; j++)
|
|
||||||
{
|
|
||||||
ICell cell = row.GetCell(j);
|
|
||||||
foreach (var property in inDto.Data.GetType().GetProperties())
|
|
||||||
{
|
|
||||||
var value = property.GetValue(inDto.Data);
|
|
||||||
if (cell!=null&&cell.ToString() == "{{" + property.Name + "}}")
|
|
||||||
{
|
|
||||||
sheet.GetRow(i).GetCell(j).SetCellValue(value.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var memoryStream2 = new MemoryStream();
|
|
||||||
workbook.Write(memoryStream2, true);
|
|
||||||
|
|
||||||
memoryStream2.Seek(0, SeekOrigin.Begin);
|
|
||||||
|
|
||||||
templateStream = memoryStream2;
|
|
||||||
|
|
||||||
|
|
||||||
return new FileStreamResult(templateStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
|
||||||
{
|
|
||||||
FileDownloadName = $"{(string.IsNullOrEmpty(inDto.ExportFileName) ? "" : inDto.ExportFileName + "_")}{Path.GetFileNameWithoutExtension(fileName)}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,14 @@
|
|||||||
using System.Diagnostics;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Helper;
|
namespace IRaCIS.Core.Application.Helper
|
||||||
|
|
||||||
public class FileConvertHelper
|
|
||||||
{
|
{
|
||||||
|
public class FileConvertHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
static public void ConvertWordToPdf(string inputWordFilePath, string outputPdfDir)
|
static public void ConvertWordToPdf(string inputWordFilePath, string outputPdfDir)
|
||||||
@@ -30,4 +35,5 @@ public class FileConvertHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
using IRaCIS.Core.Domain.Share;
|
|
||||||
|
|
||||||
|
using Aliyun.OSS;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
using IRaCIS.Core.Infrastructure;
|
using IRaCIS.Core.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System.Configuration;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
@@ -11,7 +16,7 @@ public static class FileStoreHelper
|
|||||||
{
|
{
|
||||||
|
|
||||||
//处理文件名 压缩包,或者目录类的 会带上相对路径
|
//处理文件名 压缩包,或者目录类的 会带上相对路径
|
||||||
public static (string TrustedFileNameForFileStorage, string RealName) GetStoreFileName(string fileName, bool isChangeToPdfFormat = false)
|
public static (string TrustedFileNameForFileStorage, string RealName) GetStoreFileName(string fileName,bool isChangeToPdfFormat=false)
|
||||||
{
|
{
|
||||||
|
|
||||||
//带目录层级,需要后端处理前端的路径
|
//带目录层级,需要后端处理前端的路径
|
||||||
@@ -36,14 +41,14 @@ public static class FileStoreHelper
|
|||||||
|
|
||||||
var trustedFileNameForFileStorage = string.Empty;
|
var trustedFileNameForFileStorage = string.Empty;
|
||||||
|
|
||||||
if (isChangeToPdfFormat == false)
|
if (isChangeToPdfFormat==false)
|
||||||
{
|
{
|
||||||
trustedFileNameForFileStorage = Guid.NewGuid().ToString() + fileName;
|
trustedFileNameForFileStorage= Guid.NewGuid().ToString() + fileName;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trustedFileNameForFileStorage = Guid.NewGuid().ToString() + Path.GetFileNameWithoutExtension(fileName) + ".pdf";
|
trustedFileNameForFileStorage=Guid.NewGuid().ToString() + Path.GetFileNameWithoutExtension(fileName) + ".pdf";
|
||||||
}
|
}
|
||||||
|
|
||||||
return (trustedFileNameForFileStorage, fileName);
|
return (trustedFileNameForFileStorage, fileName);
|
||||||
@@ -131,7 +136,7 @@ public static class FileStoreHelper
|
|||||||
{
|
{
|
||||||
var doc = await _commonDocumentRepository.FirstOrDefaultAsync(t => t.Code == code);
|
var doc = await _commonDocumentRepository.FirstOrDefaultAsync(t => t.Code == code);
|
||||||
|
|
||||||
var isEn_US = CultureInfo.CurrentCulture.Name != StaticData.CultureInfo.zh_CN;
|
var isEn_US = CultureInfo.CurrentCulture.Name!= "zh-CN";
|
||||||
if (doc == null)
|
if (doc == null)
|
||||||
{
|
{
|
||||||
//---数据库没有找到对应的数据模板文件,请联系系统运维人员。
|
//---数据库没有找到对应的数据模板文件,请联系系统运维人员。
|
||||||
@@ -146,7 +151,7 @@ public static class FileStoreHelper
|
|||||||
throw new BusinessValidationFailedException(StaticData.International("FileStore_TemplateFileStoragePathInvalid"));
|
throw new BusinessValidationFailedException(StaticData.International("FileStore_TemplateFileStoragePathInvalid"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (filePath, isEn_US ? doc.Name.Trim('/') : doc.NameCN.Trim('/'));
|
return (filePath, isEn_US? doc.Name.Trim('/'): doc.NameCN.Trim('/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -197,7 +202,7 @@ public static class FileStoreHelper
|
|||||||
|
|
||||||
// 获取 入组确认 PD 进展发送邮件Word|PDF 存放路径
|
// 获取 入组确认 PD 进展发送邮件Word|PDF 存放路径
|
||||||
|
|
||||||
public static (string PhysicalPath, string RelativePath, string FileRealName) GetSubjectEnrollConfirmOrPDEmailPath(IWebHostEnvironment _hostEnvironment, string fileName, Guid trialId, Guid trialSiteId, Guid subjectId, bool isChangeToPdfFormat = false)
|
public static (string PhysicalPath, string RelativePath, string FileRealName) GetSubjectEnrollConfirmOrPDEmailPath(IWebHostEnvironment _hostEnvironment, string fileName, Guid trialId, Guid trialSiteId, Guid subjectId,bool isChangeToPdfFormat=false)
|
||||||
{
|
{
|
||||||
var rootPath = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment);
|
var rootPath = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment);
|
||||||
|
|
||||||
@@ -216,7 +221,7 @@ public static class FileStoreHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static string GetSubjectVisitDicomFolderPhysicalPath(IWebHostEnvironment _hostEnvironment, Guid trialId, Guid siteId, Guid subjectId, Guid subjectVisitId)
|
public static string GetSubjectVisitDicomFolderPhysicalPath(IWebHostEnvironment _hostEnvironment,Guid trialId, Guid siteId, Guid subjectId, Guid subjectVisitId)
|
||||||
{
|
{
|
||||||
var rootPath = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment);
|
var rootPath = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment);
|
||||||
|
|
||||||
@@ -228,7 +233,7 @@ public static class FileStoreHelper
|
|||||||
#region 切换存储前
|
#region 切换存储前
|
||||||
//var rootPath = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment);
|
//var rootPath = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment);
|
||||||
#endregion
|
#endregion
|
||||||
var rootPath = Path.Combine(FileStoreHelper.GetBestStoreDisk(_hostEnvironment), StaticData.Folder.IRaCISDataFolder);
|
var rootPath = Path.Combine(FileStoreHelper.GetBestStoreDisk(_hostEnvironment), StaticData.Folder.IRaCISDataFolder) ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -241,7 +246,7 @@ public static class FileStoreHelper
|
|||||||
Directory.CreateDirectory(path);
|
Directory.CreateDirectory(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
var physicalPath = Path.Combine(path, instanceId.ToString());
|
var physicalPath = Path.Combine(path, instanceId.ToString() );
|
||||||
|
|
||||||
var relativePath = $"/{StaticData.Folder.IRaCISDataFolder}/{StaticData.Folder.TrialDataFolder}/{trialId}/{subjectId}/{subjectVisitId}/{StaticData.Folder.DicomFolder}/{studyId}/{instanceId}";
|
var relativePath = $"/{StaticData.Folder.IRaCISDataFolder}/{StaticData.Folder.TrialDataFolder}/{trialId}/{subjectId}/{subjectVisitId}/{StaticData.Folder.DicomFolder}/{studyId}/{instanceId}";
|
||||||
|
|
||||||
@@ -255,7 +260,7 @@ public static class FileStoreHelper
|
|||||||
public static string GetBestStoreDisk(IWebHostEnvironment _hostEnvironment)
|
public static string GetBestStoreDisk(IWebHostEnvironment _hostEnvironment)
|
||||||
{
|
{
|
||||||
|
|
||||||
var json = File.ReadAllText(Path.Combine(_hostEnvironment.ContentRootPath, "appsettings.json"));
|
var json = File.ReadAllText( Path.Combine(_hostEnvironment.ContentRootPath, "appsettings.json"));
|
||||||
|
|
||||||
JObject jsonObject = (JObject.Parse(json, new JsonLoadSettings() { CommentHandling = CommentHandling.Load })).IfNullThrowException();
|
JObject jsonObject = (JObject.Parse(json, new JsonLoadSettings() { CommentHandling = CommentHandling.Load })).IfNullThrowException();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
using Hangfire;
|
using Hangfire;
|
||||||
|
using IRaCIS.Core.Application.Service;
|
||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using NPOI.SS.Formula.Functions;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Helper
|
namespace IRaCIS.Core.Application.Helper
|
||||||
{
|
{
|
||||||
@@ -55,7 +65,7 @@ namespace IRaCIS.Core.Application.Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void AddOrUpdateTrialCronJob(string jobId, Guid trialId, EmailBusinessScenario businessScenario, string emailCron)
|
public static void AddOrUpdateTrialCronJob (string jobId, Guid trialId, EmailBusinessScenario businessScenario, string emailCron)
|
||||||
{
|
{
|
||||||
|
|
||||||
switch (businessScenario)
|
switch (businessScenario)
|
||||||
|
|||||||
@@ -1,105 +0,0 @@
|
|||||||
using RestSharp;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Helper;
|
|
||||||
|
|
||||||
|
|
||||||
#region 对接模型
|
|
||||||
public class HolidayCalendar
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
public string Version { get; set; }
|
|
||||||
public string Generated { get; set; }
|
|
||||||
public string Timezone { get; set; }
|
|
||||||
public string Author { get; set; }
|
|
||||||
public string URL { get; set; }
|
|
||||||
public Dictionary<string, List<HolidayYear>> Years { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class HolidayYear
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
public DateTime StartDate { get; set; }
|
|
||||||
public DateTime EndDate { get; set; }
|
|
||||||
public int Duration { get; set; }
|
|
||||||
public List<DateTime> CompDays { get; set; }
|
|
||||||
public string URL { get; set; }
|
|
||||||
public string Memo { get; set; }
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class HolidayHelper
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// github 链接:https://github.com/lanceliao/china-holiday-calender?tab=readme-ov-file
|
|
||||||
/// 接口请求参考文档:https://www.koudingke.cn/docs/zh-Hans/net-lib-docs/latest/RestSharp/Usage/Usage
|
|
||||||
/// </summary>
|
|
||||||
private static RestClient _client => new RestClient("https://www.shuyz.com/githubfiles/china-holiday-calender/master/holidayAPI.json");
|
|
||||||
|
|
||||||
private static HolidayCalendar _holidayCalendar { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
private static List<DateTime> _holidays = new List<DateTime>();
|
|
||||||
private static List<DateTime> _compensatedWorkdays = new List<DateTime>();
|
|
||||||
|
|
||||||
static HolidayHelper()
|
|
||||||
{
|
|
||||||
_holidayCalendar = _client.Get<HolidayCalendar>(new RestRequest()) ?? new HolidayCalendar();
|
|
||||||
|
|
||||||
foreach (var year in _holidayCalendar.Years.Values.SelectMany(x => x))
|
|
||||||
{
|
|
||||||
// 添加节假日到假日集合
|
|
||||||
for (DateTime date = year.StartDate; date <= year.EndDate; date = date.AddDays(1))
|
|
||||||
{
|
|
||||||
_holidays.Add(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加补班日到补班日集合
|
|
||||||
foreach (var compDay in year.CompDays)
|
|
||||||
{
|
|
||||||
_compensatedWorkdays.Add(compDay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TimeSpan GetChinaWorkTimeSpan(DateTime startDate, DateTime endDate)
|
|
||||||
{
|
|
||||||
if (startDate > endDate)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("结束日期必须大于或等于开始日期");
|
|
||||||
}
|
|
||||||
|
|
||||||
var diffTimeSpan = endDate - startDate;
|
|
||||||
|
|
||||||
// 初始化工作日数为0
|
|
||||||
int workdays = 0;
|
|
||||||
|
|
||||||
// 找出在给定日期范围内的假期和补班日
|
|
||||||
var filteredHolidays = _holidays.Where(d => d >= startDate && d <= endDate).ToList();
|
|
||||||
var filteredCompensatedWorkdays = _compensatedWorkdays.Where(d => d >= startDate && d <= endDate).ToList();
|
|
||||||
|
|
||||||
// 遍历日期范围,计算工作日 注意 这里是小于
|
|
||||||
for (DateTime date = startDate.Date; date < endDate.Date; date = date.AddDays(1))
|
|
||||||
{
|
|
||||||
// 判断是否为工作日
|
|
||||||
bool isWeekend = date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday;
|
|
||||||
bool isHoliday = filteredHolidays.Contains(date);
|
|
||||||
bool isCompensatedWorkday = filteredCompensatedWorkdays.Contains(date);
|
|
||||||
|
|
||||||
// 如果是补班日,或是平日(非假期,非周末),则算作工作日
|
|
||||||
if (isCompensatedWorkday || (!isWeekend && !isHoliday))
|
|
||||||
{
|
|
||||||
workdays++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new TimeSpan(workdays, diffTimeSpan.Hours, diffTimeSpan.Minutes, diffTimeSpan.Seconds);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
namespace IRaCIS.Core.Application.Helper;
|
|
||||||
|
|
||||||
public static class IRCEmailPasswordHelper
|
|
||||||
{
|
|
||||||
private static readonly Random Random = new Random();
|
|
||||||
|
|
||||||
//显示位数:3分之2的位数,向上取整
|
|
||||||
//取哪几个个值:最后一位和前面几位
|
|
||||||
//其他:3个***。
|
|
||||||
//比如:hlj23@126.com
|
|
||||||
//为:hlj***3@126.com
|
|
||||||
|
|
||||||
//he@126.com
|
|
||||||
//为:h*** e@126.com
|
|
||||||
|
|
||||||
public static string MaskEmail(string email)
|
|
||||||
{
|
|
||||||
|
|
||||||
// 找到 "@" 符号的位置
|
|
||||||
int atIndex = email.IndexOf('@');
|
|
||||||
|
|
||||||
string visiblePartBefore = email.Substring(0, atIndex);
|
|
||||||
|
|
||||||
string afterAt = email.Substring(atIndex + 1);
|
|
||||||
|
|
||||||
int visibleLength = (int)Math.Ceiling((double)visiblePartBefore.Length * 2 / 3);
|
|
||||||
|
|
||||||
// 替换中间两位字符为星号
|
|
||||||
string hiddenPartBeforeAt = visiblePartBefore.Substring(0, visibleLength - 1) + "***" + visiblePartBefore.Last();
|
|
||||||
|
|
||||||
|
|
||||||
// 组合隐藏和可见部分
|
|
||||||
string hiddenEmail = hiddenPartBeforeAt + "@" + afterAt;
|
|
||||||
|
|
||||||
return hiddenEmail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 密码必须包含:1)8 – 32 个字符;2)至少1个数字;3) 至少1个大写字母;4)至少1个小写字母;5)至少1个特殊字符 (~!-@#$%^&*_+?)
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string GenerateRandomPassword(int length)
|
|
||||||
{
|
|
||||||
// 必须包含的字符组
|
|
||||||
const string numbers = "0123456789";
|
|
||||||
const string upperCaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
||||||
const string lowerCaseLetters = "abcdefghijklmnopqrstuvwxyz";
|
|
||||||
const string specialCharacters = "~!-@#$%^&*_+?";
|
|
||||||
|
|
||||||
// 随机选择至少一个字符
|
|
||||||
char[] requiredCharacters =
|
|
||||||
{
|
|
||||||
numbers[Random.Next(numbers.Length)],
|
|
||||||
upperCaseLetters[Random.Next(upperCaseLetters.Length)],
|
|
||||||
lowerCaseLetters[Random.Next(lowerCaseLetters.Length)],
|
|
||||||
specialCharacters[Random.Next(specialCharacters.Length)]
|
|
||||||
};
|
|
||||||
|
|
||||||
// 构建剩余的字符集,用于填充密码的其余部分
|
|
||||||
string allCharacters = numbers + upperCaseLetters + lowerCaseLetters + specialCharacters;
|
|
||||||
|
|
||||||
// 确保密码长度满足用户要求
|
|
||||||
char[] password = new char[length];
|
|
||||||
|
|
||||||
// 将必须包含的字符放入密码中
|
|
||||||
requiredCharacters.CopyTo(password, 0);
|
|
||||||
|
|
||||||
// 填充剩余的字符
|
|
||||||
for (int i = requiredCharacters.Length; i < length; i++)
|
|
||||||
{
|
|
||||||
password[i] = allCharacters[Random.Next(allCharacters.Length)];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 随机打乱密码字符顺序
|
|
||||||
return new string(password.OrderBy(_ => Random.Next()).ToArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
|
|
||||||
using FellowOakDicom.Imaging;
|
using FellowOakDicom.Imaging;
|
||||||
using SixLabors.ImageSharp;
|
|
||||||
using SixLabors.ImageSharp.Formats.Jpeg;
|
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||||
|
using SixLabors.ImageSharp;
|
||||||
using SixLabors.ImageSharp.Processing;
|
using SixLabors.ImageSharp.Processing;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Helper;
|
namespace IRaCIS.Core.Application.Helper;
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,17 @@ using IRaCIS.Core.Infrastructure;
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static IRaCIS.Core.Application.Service.Common.SystemMonitor;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Helper;
|
namespace IRaCIS.Core.Application.Helper
|
||||||
|
|
||||||
public static class InternationalizationHelper
|
|
||||||
{
|
{
|
||||||
|
public static class InternationalizationHelper
|
||||||
|
{
|
||||||
public static string JsonFileFolder = Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources);
|
public static string JsonFileFolder = Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources);
|
||||||
|
|
||||||
public static FileSystemWatcher FileSystemWatcher_US { get; set; }
|
public static FileSystemWatcher FileSystemWatcher_US { get; set; }
|
||||||
@@ -68,7 +74,7 @@ public static class InternationalizationHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task AddOrUpdateJsonKeyValueAsync(string key, string value, string valueCN, string description)
|
public static async Task AddOrUpdateJsonKeyValueAsync(string key, string value, string valueCN,string description)
|
||||||
{
|
{
|
||||||
|
|
||||||
VerifyFolder();
|
VerifyFolder();
|
||||||
@@ -204,4 +210,5 @@ public static class InternationalizationHelper
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,139 +1,102 @@
|
|||||||
using AlibabaCloud.SDK.Sts20150401;
|
using Aliyun.OSS;
|
||||||
using Aliyun.OSS;
|
|
||||||
using Amazon;
|
|
||||||
using Amazon.Runtime;
|
|
||||||
using Amazon.S3;
|
|
||||||
using Amazon.S3.Model;
|
|
||||||
using Amazon.SecurityToken;
|
|
||||||
using Amazon.SecurityToken.Model;
|
|
||||||
using IRaCIS.Core.Infrastructure;
|
using IRaCIS.Core.Infrastructure;
|
||||||
using IRaCIS.Core.Infrastructure.NewtonsoftJson;
|
using Microsoft.Extensions.Hosting;
|
||||||
using MassTransit;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Minio;
|
|
||||||
using Minio.DataModel.Args;
|
using Minio.DataModel.Args;
|
||||||
using System.Reactive.Linq;
|
using Minio;
|
||||||
|
using SharpCompress.Common;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.AccessControl;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Helper;
|
namespace IRaCIS.Core.Application.Helper
|
||||||
|
|
||||||
#region 绑定和返回模型
|
|
||||||
|
|
||||||
[LowerCamelCaseJson]
|
|
||||||
public class MinIOOptions : AWSOptions
|
|
||||||
{
|
{
|
||||||
public int Port { get; set; }
|
public class MinIOOptions : AWSOptions
|
||||||
|
{
|
||||||
|
public int port { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class AWSOptions
|
||||||
|
{
|
||||||
|
public string endPoint { get; set; }
|
||||||
|
public bool useSSL { get; set; }
|
||||||
|
public string accessKey { get; set; }
|
||||||
|
public string secretKey { get; set; }
|
||||||
|
public string bucketName { get; set; }
|
||||||
|
public string viewEndpoint { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class AWSOptions
|
public class AliyunOSSOptions
|
||||||
{
|
{
|
||||||
public string EndPoint { get; set; }
|
public string regionId { get; set; }
|
||||||
public bool UseSSL { get; set; }
|
public string accessKeyId { get; set; }
|
||||||
public string AccessKeyId { get; set; }
|
public string accessKeySecret { get; set; }
|
||||||
public string RoleArn { get; set; }
|
|
||||||
public string SecretAccessKey { get; set; }
|
|
||||||
public string BucketName { get; set; }
|
|
||||||
public string ViewEndpoint { get; set; }
|
|
||||||
public int DurationSeconds { get; set; }
|
|
||||||
public string Region { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AliyunOSSOptions
|
public string internalEndpoint { get; set; }
|
||||||
{
|
|
||||||
public string RegionId { get; set; }
|
|
||||||
public string AccessKeyId { get; set; }
|
|
||||||
public string AccessKeySecret { get; set; }
|
|
||||||
|
|
||||||
public string InternalEndpoint { get; set; }
|
public string endPoint { get; set; }
|
||||||
|
public string bucketName { get; set; }
|
||||||
|
|
||||||
public string EndPoint { get; set; }
|
public string roleArn { get; set; }
|
||||||
public string BucketName { get; set; }
|
|
||||||
|
|
||||||
public string RoleArn { get; set; }
|
public string region { get; set; }
|
||||||
|
|
||||||
public string Region { get; set; }
|
public string viewEndpoint { get; set; }
|
||||||
|
|
||||||
public string ViewEndpoint { get; set; }
|
}
|
||||||
|
|
||||||
public int DurationSeconds { get; set; }
|
public class ObjectStoreServiceOptions
|
||||||
|
{
|
||||||
|
public string ObjectStoreUse { get; set; }
|
||||||
|
public AliyunOSSOptions AliyunOSS { get; set; }
|
||||||
|
public MinIOOptions MinIO { get; set; }
|
||||||
|
|
||||||
|
public AWSOptions AWS { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
public class ObjectStoreDTO
|
||||||
|
{
|
||||||
public class ObjectStoreServiceOptions
|
|
||||||
{
|
|
||||||
public string ObjectStoreUse { get; set; }
|
public string ObjectStoreUse { get; set; }
|
||||||
|
|
||||||
public AliyunOSSOptions AliyunOSS { get; set; }
|
public AliyunOSSOptions AliyunOSS { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public MinIOOptions MinIO { get; set; }
|
public MinIOOptions MinIO { get; set; }
|
||||||
|
|
||||||
public AWSOptions AWS { get; set; }
|
public AWSOptions AWS { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ObjectStoreDTO
|
public class AliyunOSSTempToken
|
||||||
{
|
{
|
||||||
public string ObjectStoreUse { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public AliyunOSSTempToken AliyunOSS { get; set; }
|
|
||||||
|
|
||||||
public MinIOOptions MinIO { get; set; }
|
|
||||||
|
|
||||||
public AWSTempToken AWS { get; set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[LowerCamelCaseJson]
|
|
||||||
public class AliyunOSSTempToken
|
|
||||||
{
|
|
||||||
public string AccessKeyId { get; set; }
|
public string AccessKeyId { get; set; }
|
||||||
public string AccessKeySecret { get; set; }
|
public string AccessKeySecret { get; set; }
|
||||||
|
|
||||||
public string EndPoint { get; set; }
|
|
||||||
public string BucketName { get; set; }
|
|
||||||
|
|
||||||
public string Region { get; set; }
|
|
||||||
|
|
||||||
public string ViewEndpoint { get; set; }
|
|
||||||
|
|
||||||
public string SecurityToken { get; set; }
|
public string SecurityToken { get; set; }
|
||||||
public DateTime Expiration { get; set; }
|
public string Expiration { get; set; }
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[LowerCamelCaseJson]
|
|
||||||
public class AWSTempToken
|
|
||||||
{
|
|
||||||
public string Region { get; set; }
|
public string Region { get; set; }
|
||||||
public string SessionToken { get; set; }
|
|
||||||
public string EndPoint { get; set; }
|
|
||||||
public string AccessKeyId { get; set; }
|
|
||||||
public string SecretAccessKey { get; set; }
|
|
||||||
public string BucketName { get; set; }
|
public string BucketName { get; set; }
|
||||||
public string ViewEndpoint { get; set; }
|
public string ViewEndpoint { get; set; }
|
||||||
public DateTime Expiration { get; set; }
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public enum ObjectStoreUse
|
|
||||||
{
|
|
||||||
|
public enum ObjectStoreUse
|
||||||
|
{
|
||||||
AliyunOSS = 0,
|
AliyunOSS = 0,
|
||||||
MinIO = 1,
|
MinIO = 1,
|
||||||
AWS = 2,
|
AWS = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
public interface IOSSService
|
||||||
|
{
|
||||||
// aws 参考链接 https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3/S3/S3_Basics
|
|
||||||
|
|
||||||
public interface IOSSService
|
|
||||||
{
|
|
||||||
public Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true);
|
public Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true);
|
||||||
public Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true);
|
public Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true);
|
||||||
|
|
||||||
@@ -143,29 +106,19 @@ public interface IOSSService
|
|||||||
|
|
||||||
public Task<string> GetSignedUrl(string ossRelativePath);
|
public Task<string> GetSignedUrl(string ossRelativePath);
|
||||||
|
|
||||||
public Task DeleteFromPrefix(string prefix);
|
}
|
||||||
|
|
||||||
public ObjectStoreDTO GetObjectStoreTempToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class OSSService : IOSSService
|
public class OSSService : IOSSService
|
||||||
{
|
{
|
||||||
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
|
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
|
||||||
|
|
||||||
private AliyunOSSTempToken AliyunOSSTempToken { get; set; }
|
|
||||||
|
|
||||||
private AWSTempToken AWSTempToken { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options)
|
public OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options)
|
||||||
{
|
{
|
||||||
ObjectStoreServiceOptions = options.CurrentValue;
|
ObjectStoreServiceOptions = options.CurrentValue;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
|
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -176,9 +129,9 @@ public class OSSService : IOSSService
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true)
|
public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
|
||||||
|
|
||||||
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}";
|
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}";
|
||||||
|
//var ossRelativePath = $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}";
|
||||||
|
//var ossRelativePath = oosFolderPath + "/" + fileRealName;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -195,12 +148,12 @@ public class OSSService : IOSSService
|
|||||||
{
|
{
|
||||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||||
|
|
||||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.endPoint : aliConfig.internalEndpoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 上传文件
|
// 上传文件
|
||||||
var result = _ossClient.PutObject(aliConfig.BucketName, ossRelativePath, memoryStream);
|
var result = _ossClient.PutObject(aliConfig.bucketName, ossRelativePath, memoryStream);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||||
@@ -208,12 +161,12 @@ public class OSSService : IOSSService
|
|||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var putObjectArgs = new PutObjectArgs()
|
var putObjectArgs = new PutObjectArgs()
|
||||||
.WithBucket(minIOConfig.BucketName)
|
.WithBucket(minIOConfig.bucketName)
|
||||||
.WithObject(ossRelativePath)
|
.WithObject(ossRelativePath)
|
||||||
.WithStreamData(memoryStream)
|
.WithStreamData(memoryStream)
|
||||||
.WithObjectSize(memoryStream.Length);
|
.WithObjectSize(memoryStream.Length);
|
||||||
@@ -222,29 +175,20 @@ public class OSSService : IOSSService
|
|||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||||
{
|
{
|
||||||
var awsConfig = ObjectStoreServiceOptions.AWS;
|
var minIOConfig = ObjectStoreServiceOptions.AWS;
|
||||||
|
|
||||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
|
||||||
|
|
||||||
|
|
||||||
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
|
||||||
|
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||||
|
.Build();
|
||||||
|
|
||||||
//提供awsEndPoint(域名)进行访问配置
|
var putObjectArgs = new PutObjectArgs()
|
||||||
var clientConfig = new AmazonS3Config
|
.WithBucket(minIOConfig.bucketName)
|
||||||
{
|
.WithObject(ossRelativePath)
|
||||||
RegionEndpoint = RegionEndpoint.USEast1,
|
.WithStreamData(memoryStream)
|
||||||
UseHttp = true,
|
.WithObjectSize(memoryStream.Length);
|
||||||
};
|
|
||||||
|
|
||||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
await minioClient.PutObjectAsync(putObjectArgs);
|
||||||
|
|
||||||
var putObjectRequest = new Amazon.S3.Model.PutObjectRequest()
|
|
||||||
{
|
|
||||||
BucketName = awsConfig.BucketName,
|
|
||||||
InputStream = memoryStream,
|
|
||||||
Key = ossRelativePath,
|
|
||||||
};
|
|
||||||
|
|
||||||
await amazonS3Client.PutObjectAsync(putObjectRequest);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -272,26 +216,26 @@ public class OSSService : IOSSService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="localFilePath"></param>
|
/// <param name="localFilePath"></param>
|
||||||
/// <param name="oosFolderPath"></param>
|
/// <param name="oosFolderPath"></param>
|
||||||
/// <param name="isFileNameAddGuid"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="BusinessValidationFailedException"></exception>
|
/// <exception cref="BusinessValidationFailedException"></exception>
|
||||||
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
|
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
|
||||||
|
|
||||||
var localFileName = Path.GetFileName(localFilePath);
|
var localFileName = Path.GetFileName(localFilePath);
|
||||||
|
|
||||||
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{localFileName}" : $"{oosFolderPath}/{localFileName}";
|
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{localFileName}" : $"{oosFolderPath}/{localFileName}";
|
||||||
|
|
||||||
|
|
||||||
|
//var ossRelativePath = oosFolderPath + "/" + localFileName;
|
||||||
|
|
||||||
|
|
||||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||||
{
|
{
|
||||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||||
|
|
||||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)? aliConfig.endPoint: aliConfig.internalEndpoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);
|
||||||
|
|
||||||
// 上传文件
|
// 上传文件
|
||||||
var result = _ossClient.PutObject(aliConfig.BucketName, ossRelativePath, localFilePath);
|
var result = _ossClient.PutObject(aliConfig.bucketName, ossRelativePath, localFilePath);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||||
@@ -299,12 +243,12 @@ public class OSSService : IOSSService
|
|||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var putObjectArgs = new PutObjectArgs()
|
var putObjectArgs = new PutObjectArgs()
|
||||||
.WithBucket(minIOConfig.BucketName)
|
.WithBucket(minIOConfig.bucketName)
|
||||||
.WithObject(ossRelativePath)
|
.WithObject(ossRelativePath)
|
||||||
.WithFileName(localFilePath);
|
.WithFileName(localFilePath);
|
||||||
|
|
||||||
@@ -312,29 +256,19 @@ public class OSSService : IOSSService
|
|||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||||
{
|
{
|
||||||
var awsConfig = ObjectStoreServiceOptions.AWS;
|
var minIOConfig = ObjectStoreServiceOptions.AWS;
|
||||||
|
|
||||||
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
|
|
||||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
|
||||||
|
|
||||||
//提供awsEndPoint(域名)进行访问配置
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
|
||||||
var clientConfig = new AmazonS3Config
|
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||||
{
|
.Build();
|
||||||
RegionEndpoint = RegionEndpoint.USEast1,
|
|
||||||
UseHttp = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
var putObjectArgs = new PutObjectArgs()
|
||||||
|
.WithBucket(minIOConfig.bucketName)
|
||||||
var putObjectRequest = new Amazon.S3.Model.PutObjectRequest()
|
.WithObject(ossRelativePath)
|
||||||
{
|
.WithFileName(localFilePath);
|
||||||
BucketName = awsConfig.BucketName,
|
|
||||||
FilePath = localFilePath,
|
|
||||||
Key = ossRelativePath,
|
|
||||||
};
|
|
||||||
|
|
||||||
await amazonS3Client.PutObjectAsync(putObjectRequest);
|
|
||||||
|
|
||||||
|
await minioClient.PutObjectAsync(putObjectArgs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -347,7 +281,6 @@ public class OSSService : IOSSService
|
|||||||
|
|
||||||
public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
|
public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
|
||||||
|
|
||||||
ossRelativePath = ossRelativePath.TrimStart('/');
|
ossRelativePath = ossRelativePath.TrimStart('/');
|
||||||
try
|
try
|
||||||
@@ -358,10 +291,10 @@ public class OSSService : IOSSService
|
|||||||
{
|
{
|
||||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||||
|
|
||||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.endPoint : aliConfig.internalEndpoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);
|
||||||
|
|
||||||
// 上传文件
|
// 上传文件
|
||||||
var result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);
|
var result = _ossClient.GetObject(aliConfig.bucketName, ossRelativePath);
|
||||||
|
|
||||||
// 将下载的文件流保存到本地文件
|
// 将下载的文件流保存到本地文件
|
||||||
using (var fs = File.OpenWrite(localFilePath))
|
using (var fs = File.OpenWrite(localFilePath))
|
||||||
@@ -375,12 +308,12 @@ public class OSSService : IOSSService
|
|||||||
{
|
{
|
||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var getObjectArgs = new GetObjectArgs()
|
var getObjectArgs = new GetObjectArgs()
|
||||||
.WithBucket(minIOConfig.BucketName)
|
.WithBucket(minIOConfig.bucketName)
|
||||||
.WithObject(ossRelativePath)
|
.WithObject(ossRelativePath)
|
||||||
.WithFile(localFilePath);
|
.WithFile(localFilePath);
|
||||||
|
|
||||||
@@ -389,30 +322,18 @@ public class OSSService : IOSSService
|
|||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||||
{
|
{
|
||||||
var awsConfig = ObjectStoreServiceOptions.AWS;
|
var minIOConfig = ObjectStoreServiceOptions.AWS;
|
||||||
|
|
||||||
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
|
||||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||||
|
.Build();
|
||||||
//提供awsEndPoint(域名)进行访问配置
|
|
||||||
var clientConfig = new AmazonS3Config
|
|
||||||
{
|
|
||||||
RegionEndpoint = RegionEndpoint.USEast1,
|
|
||||||
UseHttp = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
|
||||||
|
|
||||||
var getObjectArgs = new Amazon.S3.Model.GetObjectRequest()
|
|
||||||
{
|
|
||||||
BucketName = awsConfig.BucketName,
|
|
||||||
Key = ossRelativePath,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
await (await amazonS3Client.GetObjectAsync(getObjectArgs)).WriteResponseStreamToFileAsync(localFilePath, true, CancellationToken.None);
|
|
||||||
|
|
||||||
|
var getObjectArgs = new GetObjectArgs()
|
||||||
|
.WithBucket(minIOConfig.bucketName)
|
||||||
|
.WithObject(ossRelativePath)
|
||||||
|
.WithFile(localFilePath);
|
||||||
|
|
||||||
|
await minioClient.GetObjectAsync(getObjectArgs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -433,8 +354,6 @@ public class OSSService : IOSSService
|
|||||||
|
|
||||||
public async Task<string> GetSignedUrl(string ossRelativePath)
|
public async Task<string> GetSignedUrl(string ossRelativePath)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
|
||||||
|
|
||||||
ossRelativePath = ossRelativePath.TrimStart('/');
|
ossRelativePath = ossRelativePath.TrimStart('/');
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -444,10 +363,10 @@ public class OSSService : IOSSService
|
|||||||
{
|
{
|
||||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||||
|
|
||||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.endPoint : aliConfig.internalEndpoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);
|
||||||
|
|
||||||
// 生成签名URL。
|
// 生成签名URL。
|
||||||
var req = new GeneratePresignedUriRequest(aliConfig.BucketName, ossRelativePath, SignHttpMethod.Get)
|
var req = new GeneratePresignedUriRequest(aliConfig.bucketName, ossRelativePath, SignHttpMethod.Get)
|
||||||
{
|
{
|
||||||
// 设置签名URL过期时间,默认值为3600秒。
|
// 设置签名URL过期时间,默认值为3600秒。
|
||||||
Expiration = DateTime.Now.AddHours(1),
|
Expiration = DateTime.Now.AddHours(1),
|
||||||
@@ -461,13 +380,13 @@ public class OSSService : IOSSService
|
|||||||
{
|
{
|
||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
|
||||||
var args = new PresignedGetObjectArgs()
|
var args = new PresignedGetObjectArgs()
|
||||||
.WithBucket(minIOConfig.BucketName)
|
.WithBucket(minIOConfig.bucketName)
|
||||||
.WithObject(ossRelativePath)
|
.WithObject(ossRelativePath)
|
||||||
.WithExpiry(3600)
|
.WithExpiry(3600)
|
||||||
/*.WithHeaders(reqParams)*/;
|
/*.WithHeaders(reqParams)*/;
|
||||||
@@ -484,27 +403,18 @@ public class OSSService : IOSSService
|
|||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||||
{
|
{
|
||||||
var awsConfig = ObjectStoreServiceOptions.AWS;
|
var minIOConfig = ObjectStoreServiceOptions.AWS;
|
||||||
|
|
||||||
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
|
||||||
|
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||||
|
.Build();
|
||||||
|
|
||||||
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
|
var args = new PresignedGetObjectArgs()
|
||||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
.WithBucket(minIOConfig.bucketName)
|
||||||
|
.WithObject(ossRelativePath)
|
||||||
|
.WithExpiry(3600);
|
||||||
|
|
||||||
//提供awsEndPoint(域名)进行访问配置
|
var presignedUrl = await minioClient.PresignedGetObjectAsync(args);
|
||||||
var clientConfig = new AmazonS3Config
|
|
||||||
{
|
|
||||||
RegionEndpoint = RegionEndpoint.USEast1,
|
|
||||||
UseHttp = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
|
||||||
|
|
||||||
var presignedUrl = await amazonS3Client.GetPreSignedURLAsync(new GetPreSignedUrlRequest()
|
|
||||||
{
|
|
||||||
BucketName = awsConfig.BucketName,
|
|
||||||
Key = ossRelativePath,
|
|
||||||
Expires = DateTime.UtcNow.AddMinutes(120)
|
|
||||||
});
|
|
||||||
|
|
||||||
Uri uri = new Uri(presignedUrl);
|
Uri uri = new Uri(presignedUrl);
|
||||||
|
|
||||||
@@ -525,246 +435,7 @@ public class OSSService : IOSSService
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 删除某个目录的文件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="prefix"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task DeleteFromPrefix(string prefix)
|
|
||||||
{
|
|
||||||
GetObjectStoreTempToken();
|
|
||||||
|
|
||||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
|
||||||
{
|
|
||||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
|
||||||
|
|
||||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
|
||||||
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ObjectListing objectListing = null;
|
|
||||||
string nextMarker = null;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// 使用 prefix 模拟目录结构,设置 MaxKeys 和 NextMarker
|
|
||||||
objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(aliConfig.BucketName)
|
|
||||||
{
|
|
||||||
Prefix = prefix,
|
|
||||||
MaxKeys = 1000,
|
|
||||||
Marker = nextMarker
|
|
||||||
});
|
|
||||||
|
|
||||||
List<string> keys = objectListing.ObjectSummaries.Select(t => t.Key).ToList();
|
|
||||||
|
|
||||||
// 删除获取到的文件
|
|
||||||
if (keys.Count > 0)
|
|
||||||
{
|
|
||||||
_ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(aliConfig.BucketName, keys, false));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置 NextMarker 以获取下一页的数据
|
|
||||||
nextMarker = objectListing.NextMarker;
|
|
||||||
|
|
||||||
} while (objectListing.IsTruncated);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Error: {ex.Message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
|
||||||
{
|
|
||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
|
||||||
|
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
|
|
||||||
var listArgs = new ListObjectsArgs().WithBucket(minIOConfig.BucketName).WithPrefix(prefix).WithRecursive(true);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 创建一个空列表用于存储对象键
|
|
||||||
var objects = new List<string>();
|
|
||||||
|
|
||||||
// 使用 await foreach 来异步迭代对象列表
|
|
||||||
await foreach (var item in minioClient.ListObjectsEnumAsync(listArgs))
|
|
||||||
{
|
|
||||||
objects.Add(item.Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (objects.Count > 0)
|
|
||||||
{
|
|
||||||
var objArgs = new RemoveObjectsArgs()
|
|
||||||
.WithBucket(minIOConfig.BucketName)
|
|
||||||
.WithObjects(objects);
|
|
||||||
|
|
||||||
// 删除对象
|
|
||||||
await minioClient.RemoveObjectsAsync(objArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
|
||||||
{
|
|
||||||
|
|
||||||
var awsConfig = ObjectStoreServiceOptions.AWS;
|
|
||||||
|
|
||||||
|
|
||||||
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
|
|
||||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
|
||||||
|
|
||||||
//提供awsEndPoint(域名)进行访问配置
|
|
||||||
var clientConfig = new AmazonS3Config
|
|
||||||
{
|
|
||||||
RegionEndpoint = RegionEndpoint.USEast1,
|
|
||||||
UseHttp = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
|
||||||
|
|
||||||
// 列出指定前缀下的所有对象
|
|
||||||
var listObjectsRequest = new ListObjectsV2Request
|
|
||||||
{
|
|
||||||
BucketName = awsConfig.BucketName,
|
|
||||||
Prefix = prefix
|
|
||||||
};
|
|
||||||
|
|
||||||
var listObjectsResponse = await amazonS3Client.ListObjectsV2Async(listObjectsRequest);
|
|
||||||
|
|
||||||
if (listObjectsResponse.S3Objects.Count > 0)
|
|
||||||
{
|
|
||||||
// 准备删除请求
|
|
||||||
var deleteObjectsRequest = new Amazon.S3.Model.DeleteObjectsRequest
|
|
||||||
{
|
|
||||||
BucketName = awsConfig.BucketName,
|
|
||||||
Objects = new List<KeyVersion>()
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var s3Object in listObjectsResponse.S3Objects)
|
|
||||||
{
|
|
||||||
deleteObjectsRequest.Objects.Add(new KeyVersion
|
|
||||||
{
|
|
||||||
Key = s3Object.Key
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 批量删除对象
|
|
||||||
var deleteObjectsResponse = await amazonS3Client.DeleteObjectsAsync(deleteObjectsRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public ObjectStoreDTO GetObjectStoreTempToken()
|
|
||||||
{
|
|
||||||
|
|
||||||
var ossOptions = ObjectStoreServiceOptions.AliyunOSS;
|
|
||||||
|
|
||||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
|
||||||
{
|
|
||||||
var client = new Client(new AlibabaCloud.OpenApiClient.Models.Config()
|
|
||||||
{
|
|
||||||
AccessKeyId = ossOptions.AccessKeyId,
|
|
||||||
AccessKeySecret = ossOptions.AccessKeySecret,
|
|
||||||
//AccessKeyId = "LTAI5tJV76pYX5yPg1N9QVE8",
|
|
||||||
//AccessKeySecret = "roRNLa9YG1of4pYruJGCNKBXEWTAWa",
|
|
||||||
|
|
||||||
Endpoint = "sts.cn-hangzhou.aliyuncs.com"
|
|
||||||
});
|
|
||||||
|
|
||||||
var assumeRoleRequest = new AlibabaCloud.SDK.Sts20150401.Models.AssumeRoleRequest();
|
|
||||||
// 将<YOUR_ROLE_SESSION_NAME>设置为自定义的会话名称,例如oss-role-session。
|
|
||||||
assumeRoleRequest.RoleSessionName = $"session-name-{NewId.NextGuid()}";
|
|
||||||
// 将<YOUR_ROLE_ARN>替换为拥有上传文件到指定OSS Bucket权限的RAM角色的ARN。
|
|
||||||
assumeRoleRequest.RoleArn = ossOptions.RoleArn;
|
|
||||||
//assumeRoleRequest.RoleArn = "acs:ram::1899121822495495:role/webdirect";
|
|
||||||
assumeRoleRequest.DurationSeconds = ossOptions.DurationSeconds;
|
|
||||||
var runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions();
|
|
||||||
var response = client.AssumeRoleWithOptions(assumeRoleRequest, runtime);
|
|
||||||
var credentials = response.Body.Credentials;
|
|
||||||
|
|
||||||
var tempToken = new AliyunOSSTempToken()
|
|
||||||
{
|
|
||||||
AccessKeyId = credentials.AccessKeyId,
|
|
||||||
AccessKeySecret = credentials.AccessKeySecret,
|
|
||||||
|
|
||||||
//转为服务器时区,最后统一转为客户端时区
|
|
||||||
Expiration = TimeZoneInfo.ConvertTimeFromUtc(DateTime.Parse(credentials.Expiration), TimeZoneInfo.Local),
|
|
||||||
SecurityToken = credentials.SecurityToken,
|
|
||||||
|
|
||||||
|
|
||||||
Region = ossOptions.Region,
|
|
||||||
BucketName = ossOptions.BucketName,
|
|
||||||
EndPoint = ossOptions.EndPoint,
|
|
||||||
ViewEndpoint = ossOptions.ViewEndpoint,
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
AliyunOSSTempToken = tempToken;
|
|
||||||
|
|
||||||
return new ObjectStoreDTO() { ObjectStoreUse = ObjectStoreServiceOptions.ObjectStoreUse, AliyunOSS = tempToken };
|
|
||||||
}
|
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
|
||||||
{
|
|
||||||
return new ObjectStoreDTO() { ObjectStoreUse = ObjectStoreServiceOptions.ObjectStoreUse, MinIO = ObjectStoreServiceOptions.MinIO };
|
|
||||||
}
|
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
|
||||||
{
|
|
||||||
var awsOptions = ObjectStoreServiceOptions.AWS;
|
|
||||||
|
|
||||||
//aws 临时凭证
|
|
||||||
// 创建 STS 客户端
|
|
||||||
var stsClient = new AmazonSecurityTokenServiceClient(awsOptions.AccessKeyId, awsOptions.SecretAccessKey);
|
|
||||||
|
|
||||||
// 使用 AssumeRole 请求临时凭证
|
|
||||||
var assumeRoleRequest = new AssumeRoleRequest
|
|
||||||
{
|
|
||||||
|
|
||||||
RoleArn = awsOptions.RoleArn, // 角色 ARN
|
|
||||||
RoleSessionName = $"session-name-{NewId.NextGuid()}",
|
|
||||||
DurationSeconds = awsOptions.DurationSeconds // 临时凭证有效期
|
|
||||||
};
|
|
||||||
|
|
||||||
var assumeRoleResponse = stsClient.AssumeRoleAsync(assumeRoleRequest).Result;
|
|
||||||
|
|
||||||
var credentials = assumeRoleResponse.Credentials;
|
|
||||||
|
|
||||||
var tempToken = new AWSTempToken()
|
|
||||||
{
|
|
||||||
AccessKeyId = credentials.AccessKeyId,
|
|
||||||
SecretAccessKey = credentials.SecretAccessKey,
|
|
||||||
SessionToken = credentials.SessionToken,
|
|
||||||
Expiration = credentials.Expiration,
|
|
||||||
Region = awsOptions.Region,
|
|
||||||
BucketName = awsOptions.BucketName,
|
|
||||||
EndPoint = awsOptions.EndPoint,
|
|
||||||
ViewEndpoint = awsOptions.ViewEndpoint,
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
AWSTempToken = tempToken;
|
|
||||||
return new ObjectStoreDTO() { ObjectStoreUse = ObjectStoreServiceOptions.ObjectStoreUse, AWS = tempToken };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user