dicom dir 增加字段,修改下载接口
continuous-integration/drone/push Build is passing Details

Test_HIR_Net8
hang 2025-08-26 10:07:59 +08:00
parent 02f3bfbfdd
commit e7261b1c7e
24 changed files with 20425 additions and 99 deletions

View File

@ -0,0 +1,42 @@
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.Helper
{
public static class SafeBussinessHelper
{
public static async Task<bool> RunAsync(Func<Task> func, [CallerMemberName] string caller = "", string errorMsgTitle = "")
{
try
{
await func();
return true;
}
catch (Exception ex)
{
Log.Logger.Error($"【{errorMsgTitle}失败 - {caller}】: {ex.Message}");
return false;
}
}
public static async Task<(bool Success, T? Result)> RunAsync<T>(Func<Task<T>> func, [CallerMemberName] string caller = "", string errorMsgTitle = "")
{
try
{
var result = await func();
return (true, result);
}
catch (Exception ex)
{
Log.Logger.Error($"【{errorMsgTitle}失败 - {caller}】: {ex.Message}");
return (false, default);
}
}
}
}

View File

@ -227,7 +227,11 @@ namespace IRaCIS.Core.SCP.Service
{ {
foreach (var item in findCmoveInfo.HopitalGroupIdList) foreach (var item in findCmoveInfo.HopitalGroupIdList)
{ {
await _studyGroupRepository.AddAsync(new SCPStudyHospitalGroup() { SCPStudyId = g.Key.SCPStudyId, HospitalGroupId = item }); if (!_studyGroupRepository.Any(t => t.SCPStudyId == g.Key.SCPStudyId && t.HospitalGroupId == item))
{
await _studyGroupRepository.AddAsync(new SCPStudyHospitalGroup() { SCPStudyId = g.Key.SCPStudyId, HospitalGroupId = item });
}
} }
} }
else else

View File

@ -12,6 +12,7 @@ using IRaCIS.Core.SCP.Service;
using IRaCIS.Core.Infra.EFCore; using IRaCIS.Core.Infra.EFCore;
using MassTransit; using MassTransit;
using Serilog.Sinks.File; using Serilog.Sinks.File;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Core.SCP.Service namespace IRaCIS.Core.SCP.Service
{ {
@ -149,6 +150,10 @@ namespace IRaCIS.Core.SCP.Service
Id = studyId, Id = studyId,
StudyInstanceUid = studyInstanceUid, StudyInstanceUid = studyInstanceUid,
StudyTime = studyTime, StudyTime = studyTime,
DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty),
DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty),
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty), Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
//ModalityForEdit = modalityForEdit, //ModalityForEdit = modalityForEdit,
Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty), Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
@ -200,6 +205,9 @@ namespace IRaCIS.Core.SCP.Service
//SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay), //SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay),
//SeriesTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.SeriesDate) + dataset.GetSingleValue<string>(DicomTag.SeriesTime), out DateTime dt) ? dt : null, //SeriesTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.SeriesDate) + dataset.GetSingleValue<string>(DicomTag.SeriesTime), out DateTime dt) ? dt : null,
SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.SeriesDate).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.SeriesTime).TimeOfDay), SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.SeriesDate).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.SeriesTime).TimeOfDay),
DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty),
DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty),
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty), Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty), Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty), SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
@ -222,6 +230,13 @@ namespace IRaCIS.Core.SCP.Service
++findStudy.SeriesCount; ++findStudy.SeriesCount;
} }
var transferSyntaxUID = dataset.GetSingleValueOrDefault(DicomTag.TransferSyntaxUID, string.Empty);
var isEncapsulated = false;
if (transferSyntaxUID.IsNotNullOrEmpty())
{
isEncapsulated = DicomTransferSyntax.Lookup(DicomUID.Parse(transferSyntaxUID)).IsEncapsulated;
}
if (findInstance == null) if (findInstance == null)
{ {
@ -235,6 +250,12 @@ namespace IRaCIS.Core.SCP.Service
SeriesInstanceUid = findSerice.SeriesInstanceUid, SeriesInstanceUid = findSerice.SeriesInstanceUid,
SopInstanceUid = sopInstanceUid, SopInstanceUid = sopInstanceUid,
SOPClassUID= dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty),
MediaStorageSOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty),
TransferSyntaxUID = transferSyntaxUID,
MediaStorageSOPInstanceUID = dataset.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty),
IsEncapsulated = DicomTransferSyntax.Lookup(DicomUID.Parse(dataset.GetSingleValueOrDefault(DicomTag.TransferSyntaxUID, string.Empty))).IsEncapsulated,
InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1), InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),
InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.ContentDate).Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.ContentTime).TimeOfDay), InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.ContentDate).Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.ContentTime).TimeOfDay),
//InstanceTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.ContentDate) + dataset.GetSingleValue<string>(DicomTag.ContentTime), out DateTime dt) ? dt : null, //InstanceTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.ContentDate) + dataset.GetSingleValue<string>(DicomTag.ContentTime), out DateTime dt) ? dt : null,

View File

@ -81,7 +81,6 @@
<PackageReference Include="Hangfire.InMemory" Version="1.0.0" /> <PackageReference Include="Hangfire.InMemory" Version="1.0.0" />
<PackageReference Include="Hangfire.SqlServer" Version="1.8.20" /> <PackageReference Include="Hangfire.SqlServer" Version="1.8.20" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
<PackageReference Include="Serilog.Formatting.Compact" Version="3.0.0" /> <PackageReference Include="Serilog.Formatting.Compact" Version="3.0.0" />
<PackageReference Include="Serilog.Sinks.Email" Version="4.0.0" /> <PackageReference Include="Serilog.Sinks.Email" Version="4.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />

View File

@ -3,6 +3,7 @@ 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.Logging; using Microsoft.Extensions.Logging;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace IRaCIS.Core.Application.Service.BusinessFilter; namespace IRaCIS.Core.Application.Service.BusinessFilter;

View File

@ -10,5 +10,6 @@ global using Microsoft.Extensions.Localization;
global using AutoMapper; global using AutoMapper;
global using IRaCIS.Core.Domain.Share; global using IRaCIS.Core.Domain.Share;
global using IRaCIS.Core.Application.BusinessFilter; global using IRaCIS.Core.Application.BusinessFilter;
global using Serilog;

View File

@ -0,0 +1,190 @@
using FellowOakDicom;
using FellowOakDicom.Media;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.Helper
{
public class StudyDIRInfo
{
public Guid SubjectVisitId { get; set; }
// Study
public Guid DicomStudyId { get; set; }
public string PatientId { get; set; }
public string PatientName { get; set; }
public string PatientBirthDate { get; set; }
public string PatientSex { get; set; }
public string StudyInstanceUid { get; set; }
public string StudyId { get; set; }
public string DicomStudyDate { get; set; }
public string DicomStudyTime { get; set; }
public string AccessionNumber { get; set; }
public string StudyDescription { get; set; }
// Series
public string SeriesInstanceUid { get; set; }
public string Modality { get; set; }
public string DicomSeriesDate { get; set; }
public string DicomSeriesTime { get; set; }
public int SeriesNumber { get; set; }
public string SeriesDescription { get; set; }
// Instance
public Guid InstanceId { get; set; }
public string SopInstanceUid { get; set; }
public string SOPClassUID { get; set; }
public int InstanceNumber { get; set; }
public string MediaStorageSOPClassUID { get; set; }
public string MediaStorageSOPInstanceUID { get; set; }
public string TransferSyntaxUID { get; set; }
}
public static class DicomDIRHelper
{
public static async Task GenerateStudyDIRAndUploadAsync(List<StudyDIRInfo> list, Dictionary<string, string> dic, string ossFolder, IOSSService _oSSService)
{
var mappings = new List<string>();
int index = 1;
var dicomDir = new DicomDirectory();
foreach (var item in list.OrderBy(t => t.SeriesNumber).ThenBy(t => t.InstanceNumber))
{
var dicomUid = DicomUID.Enumerate().FirstOrDefault(uid => uid.UID == item.TransferSyntaxUID);
if (dicomUid != null)
{
var ts = DicomTransferSyntax.Query(dicomUid);
var dataset = new DicomDataset(ts)
{
{ DicomTag.PatientID, item.PatientId ?? string.Empty },
{ DicomTag.PatientName, item.PatientName ?? string.Empty },
{ DicomTag.PatientBirthDate, item.PatientBirthDate ?? string.Empty },
{ DicomTag.PatientSex, item.PatientSex ?? string.Empty },
{ DicomTag.StudyInstanceUID, item.StudyInstanceUid ?? string.Empty },
{ DicomTag.StudyID, item.StudyId ?? string.Empty },
{ DicomTag.StudyDate, item.DicomStudyDate ?? string.Empty },
{ DicomTag.StudyTime, item.DicomStudyTime ?? string.Empty },
{ DicomTag.AccessionNumber, item.AccessionNumber ?? string.Empty },
{ DicomTag.StudyDescription, item.StudyDescription ?? string.Empty },
{ DicomTag.SeriesInstanceUID, item.SeriesInstanceUid ?? string.Empty },
{ DicomTag.Modality, item.Modality ?? string.Empty },
{ DicomTag.SeriesDate, item.DicomSeriesDate ?? string.Empty },
{ DicomTag.SeriesTime, item.DicomSeriesTime ?? string.Empty },
{ DicomTag.SeriesNumber, item.SeriesNumber.ToString() ?? string.Empty },
{ DicomTag.SeriesDescription, item.SeriesDescription ?? string.Empty },
{ DicomTag.SOPInstanceUID, item.SopInstanceUid ?? string.Empty },
{ DicomTag.SOPClassUID, item.SOPClassUID ?? string.Empty },
{ DicomTag.InstanceNumber, item.InstanceNumber.ToString() ?? string.Empty },
{ DicomTag.MediaStorageSOPClassUID, item.MediaStorageSOPClassUID ?? string.Empty },
{ DicomTag.MediaStorageSOPInstanceUID, item.MediaStorageSOPInstanceUID ?? string.Empty },
{ DicomTag.TransferSyntaxUID, item.TransferSyntaxUID ?? string.Empty },
};
var dicomFile = new DicomFile(dataset);
// 文件名递增格式IM_00001, IM_00002, ...
string filename = $@"IMAGE/IM_{index:D5}"; // :D5 表示补足5位
mappings.Add($"{filename} => {item.InstanceId}");
dic.Add(item.InstanceId.ToString(), Path.GetFileName(filename));
dicomDir.AddFile(dicomFile, filename);
index++;
}
}
//有实际的文件
if (mappings.Count > 0)
{
#region 写入临时路径
var tempFilePath = Path.GetTempFileName();
// 保存 DICOMDIR 到临时文件 不能直接写入到流种
await dicomDir.SaveAsync(tempFilePath);
using (var memoryStream = new MemoryStream(File.ReadAllBytes(tempFilePath)))
{
// 重置流位置
memoryStream.Position = 0;
await _oSSService.UploadToOSSAsync(memoryStream, ossFolder, "DICOMDIR", false);
}
//清理临时文件
File.Delete(tempFilePath);
#endregion
#region 映射上传
// 将映射写入内存流
var mappingText = string.Join(Environment.NewLine, mappings);
await using var mappingStream = new MemoryStream(Encoding.UTF8.GetBytes(mappingText));
await _oSSService.UploadToOSSAsync(mappingStream, ossFolder, $"Download_{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}", false);
#endregion
}
}
public static StudyDIRInfo ReadDicomDIRInfo(DicomFile dicomFile)
{
var dataset = dicomFile.Dataset;
var info = new StudyDIRInfo
{
PatientId = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
StudyInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty),
StudyId = dataset.GetSingleValueOrDefault(DicomTag.StudyID, string.Empty),
DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty),
DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty),
AccessionNumber = dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty),
StudyDescription = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
SeriesInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty),
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty),
DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty),
SeriesNumber = dataset.GetSingleValueOrDefault(DicomTag.SeriesNumber, 1),
SeriesDescription = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
SopInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.SOPInstanceUID, string.Empty),
SOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty),
InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),
MediaStorageSOPClassUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty),
MediaStorageSOPInstanceUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty),
TransferSyntaxUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.TransferSyntaxUID, string.Empty)
};
return info;
}
}
}

View File

@ -1,5 +1,6 @@
using AlibabaCloud.SDK.Sts20150401; using AlibabaCloud.SDK.Sts20150401;
using Aliyun.OSS; using Aliyun.OSS;
using Aliyun.OSS.Common;
using Amazon; using Amazon;
using Amazon.Runtime; using Amazon.Runtime;
using Amazon.S3; using Amazon.S3;
@ -9,32 +10,24 @@ using Amazon.SecurityToken.Model;
using IRaCIS.Core.Infrastructure; using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.NewtonsoftJson; using IRaCIS.Core.Infrastructure.NewtonsoftJson;
using MassTransit; using MassTransit;
using MassTransit.Caching.Internals;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Minio; using Minio;
using Minio.DataModel;
using Minio.DataModel.Args; using Minio.DataModel.Args;
using Newtonsoft.Json; using Minio.Exceptions;
using System.Net;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Web;
namespace IRaCIS.Core.Application.Helper; namespace IRaCIS.Core.Application.Helper;
#region 绑定和返回模型 #region 绑定和返回模型
[LowerCamelCaseJson] [LowerCamelCaseJson]
public class MinIOOptions public class MinIOOptions : AWSOptions
{ {
public int Port { get; set; } public int Port { get; set; }
public string EndPoint { get; set; }
public bool UseSSL { get; set; }
[JsonProperty("accessKey")]
public string AccessKeyId { get; set; }
[JsonProperty("secretKey")]
public string SecretAccessKey { get; set; }
public string BucketName { get; set; }
public string ViewEndpoint { get; set; }
} }
@ -43,19 +36,13 @@ public class AWSOptions
{ {
public string EndPoint { get; set; } public string EndPoint { get; set; }
public bool UseSSL { get; set; } public bool UseSSL { get; set; }
[JsonProperty("AccessKey")]
public string AccessKeyId { get; set; } public string AccessKeyId { get; set; }
public string RoleArn { get; set; } public string RoleArn { get; set; }
[JsonProperty("SecretKey")]
public string SecretAccessKey { 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 int DurationSeconds { get; set; } public int DurationSeconds { get; set; }
public string Region { get; set; } public string Region { get; set; }
public string viewEndpoint { get; set; }
} }
public class AliyunOSSOptions public class AliyunOSSOptions
@ -77,7 +64,7 @@ public class AliyunOSSOptions
public int DurationSeconds { get; set; } public int DurationSeconds { get; set; }
public string PreviewEndpoint { get; set; }
} }
@ -123,6 +110,9 @@ public class AliyunOSSTempToken
public string SecurityToken { get; set; } public string SecurityToken { get; set; }
public DateTime Expiration { get; set; } public DateTime Expiration { get; set; }
public string PreviewEndpoint { get; set; }
public string DownloadEndPoint => EndPoint.Insert(EndPoint.IndexOf("//") + 2, BucketName + ".");
} }
@ -136,7 +126,7 @@ public class AWSTempToken
public string SecretAccessKey { 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 DateTime? Expiration { get; set; }
} }
public enum ObjectStoreUse public enum ObjectStoreUse
@ -157,13 +147,23 @@ public interface IOSSService
public Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath); public Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath);
public Task<Stream> GetStreamFromOSSAsync(string ossRelativePath);
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; } public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
public Task<string> GetSignedUrl(string ossRelativePath); public Task<string> GetSignedUrl(string ossRelativePath);
public Task DeleteFromPrefix(string prefix); public Task DeleteFromPrefix(string prefix, bool isCache = false);
public Task DeleteObjects(List<string> objectKeys);
List<string> GetRootFolderNames();
public ObjectStoreDTO GetObjectStoreTempToken(); public ObjectStoreDTO GetObjectStoreTempToken();
public Task MoveObject(string sourcePath, string destPath, bool overwrite = true);
public Task<long> GetObjectSizeAsync(string sourcePath);
} }
@ -194,7 +194,7 @@ 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(); BackBatchGetToken();
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}"; var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}";
@ -223,17 +223,11 @@ public class OSSService : IOSSService
} }
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO") else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
{ {
var httpClientHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
};
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.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
.WithHttpClient(new HttpClient(httpClientHandler))
.Build(); .Build();
var putObjectArgs = new PutObjectArgs() var putObjectArgs = new PutObjectArgs()
@ -290,6 +284,37 @@ public class OSSService : IOSSService
} }
//后端批量上传 或者下载不每个文件获取临时token
private void BackBatchGetToken()
{
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
{
if (AliyunOSSTempToken == null)
{
GetObjectStoreTempToken();
}
//token 过期了
else if (AliyunOSSTempToken.Expiration.AddSeconds(10) <= DateTime.Now)
{
GetObjectStoreTempToken();
}
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
{
if (AWSTempToken == null)
{
GetObjectStoreTempToken();
}
//token 过期了
else if (AWSTempToken.Expiration?.AddSeconds(10) <= DateTime.Now)
{
GetObjectStoreTempToken();
}
}
}
/// <summary> /// <summary>
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder /// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
@ -301,7 +326,7 @@ public class OSSService : IOSSService
/// <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(); BackBatchGetToken();
var localFileName = Path.GetFileName(localFilePath); var localFileName = Path.GetFileName(localFilePath);
@ -320,18 +345,11 @@ public class OSSService : IOSSService
} }
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO") else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
{ {
var httpClientHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
};
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.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
.WithHttpClient(new HttpClient(httpClientHandler))
.Build(); .Build();
var putObjectArgs = new PutObjectArgs() var putObjectArgs = new PutObjectArgs()
@ -378,7 +396,7 @@ public class OSSService : IOSSService
public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath) public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
{ {
GetObjectStoreTempToken(); BackBatchGetToken();
ossRelativePath = ossRelativePath.TrimStart('/'); ossRelativePath = ossRelativePath.TrimStart('/');
try try
@ -391,33 +409,23 @@ public class OSSService : IOSSService
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, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
// 上传文件
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))
{ {
result.Content.CopyTo(fs); await result.Content.CopyToAsync(fs);
fs.Close();
} }
} }
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO") else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
{ {
var httpClientHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
};
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.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
.WithHttpClient(new HttpClient(httpClientHandler))
.Build(); .Build();
var getObjectArgs = new GetObjectArgs() var getObjectArgs = new GetObjectArgs()
.WithBucket(minIOConfig.BucketName) .WithBucket(minIOConfig.BucketName)
.WithObject(ossRelativePath) .WithObject(ossRelativePath)
@ -470,6 +478,96 @@ public class OSSService : IOSSService
} }
public async Task<Stream> GetStreamFromOSSAsync(string ossRelativePath)
{
BackBatchGetToken();
ossRelativePath = ossRelativePath.TrimStart('/');
try
{
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
);
var result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);
// 将OSS返回的流复制到内存流中并返回
var memoryStream = new MemoryStream();
await result.Content.CopyToAsync(memoryStream);
memoryStream.Position = 0; // 重置位置以便读取
return memoryStream;
}
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 memoryStream = new MemoryStream();
var getObjectArgs = new GetObjectArgs()
.WithBucket(minIOConfig.BucketName)
.WithObject(ossRelativePath)
.WithCallbackStream(stream => stream.CopyToAsync(memoryStream));
await minioClient.GetObjectAsync(getObjectArgs);
memoryStream.Position = 0;
return memoryStream;
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
{
var awsConfig = ObjectStoreServiceOptions.AWS;
var credentials = new SessionAWSCredentials(
AWSTempToken.AccessKeyId,
AWSTempToken.SecretAccessKey,
AWSTempToken.SessionToken
);
var clientConfig = new AmazonS3Config
{
RegionEndpoint = RegionEndpoint.USEast1,
UseHttp = true,
};
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
var getObjectRequest = new Amazon.S3.Model.GetObjectRequest
{
BucketName = awsConfig.BucketName,
Key = ossRelativePath
};
var response = await amazonS3Client.GetObjectAsync(getObjectRequest);
var memoryStream = new MemoryStream();
await response.ResponseStream.CopyToAsync(memoryStream);
memoryStream.Position = 0;
return memoryStream;
}
else
{
throw new BusinessValidationFailedException("未定义的存储介质类型");
}
}
catch (Exception ex)
{
throw new BusinessValidationFailedException("oss流获取失败! " + ex.Message);
}
}
public async Task<string> GetSignedUrl(string ossRelativePath) public async Task<string> GetSignedUrl(string ossRelativePath)
{ {
GetObjectStoreTempToken(); GetObjectStoreTempToken();
@ -565,12 +663,240 @@ public class OSSService : IOSSService
} }
/// <summary>
/// 移动OSS文件到新路径
/// </summary>
/// <param name="sourcePath">原文件路径格式bucket/key</param>
/// <param name="destPath">新文件路径格式bucket/key</param>
/// <param name="overwrite">是否覆盖已存在的目标文件默认true</param>
public async Task MoveObject(string sourcePath, string destPath, bool overwrite = true)
{
GetObjectStoreTempToken();
switch (ObjectStoreServiceOptions.ObjectStoreUse)
{
case "AliyunOSS":
#region 阿里云
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
var client = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
if (sourcePath.StartsWith("/"))
{
sourcePath = sourcePath.Substring(1);
}
if (destPath.StartsWith("/"))
{
destPath = destPath.Substring(1);
}
var sourceBucket = aliConfig.BucketName;
var sourceKey = sourcePath;
var destBucket = aliConfig.BucketName;
var destKey = destPath;
try
{
// 检查目标是否存在(当不允许覆盖时)
if (!overwrite && client.DoesObjectExist(destBucket, destKey))
{
throw new InvalidOperationException("File Exist");
}
//var copyRequest = new Aliyun.OSS.CopyObjectRequest(sourceBucket, sourceKey, sourceBucket, destKey);
//var result = client.CopyObject(copyRequest);
//// 2. 删除原文件(可选,根据是否需要保留原文件)
//client.DeleteObject(sourceBucket, sourceKey);
// 执行复制
var copyRequestAli = new Aliyun.OSS.CopyObjectRequest(
sourceBucket, sourceKey,
destBucket, destKey);
// 保持原文件元数据
copyRequestAli.NewObjectMetadata = new ObjectMetadata
{
ContentType = client.GetObjectMetadata(sourceBucket, sourceKey).ContentType
};
var result = client.CopyObject(copyRequestAli);
// 删除原文件(仅在复制成功后)
client.DeleteObject(sourceBucket, sourceKey);
}
catch (OssException ex)
{
throw new Exception($"[{ex.ErrorCode}] {ex.Message}", ex);
}
#endregion
break;
case "MinIO":
#region MinIO
var minIOConfig = ObjectStoreServiceOptions.MinIO;
var minioClient = new MinioClient()
.WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey)
.WithSSL(minIOConfig.UseSSL)
.Build();
// 定义源路径和目标路径
string destinationKey = "b路径/文件名";
try
{
// 1. 复制文件到新路径[2,5](@ref)
using (var memoryStream = new MemoryStream())
{
// 下载源文件流
await minioClient.GetObjectAsync(new GetObjectArgs()
.WithBucket(minIOConfig.BucketName)
.WithObject(sourcePath)
.WithCallbackStream(stream => stream.CopyTo(memoryStream)));
memoryStream.Position = 0; // 重置流位置
// 上传到新路径
await minioClient.PutObjectAsync(new PutObjectArgs()
.WithBucket(minIOConfig.BucketName)
.WithObject(destinationKey)
.WithStreamData(memoryStream)
.WithObjectSize(memoryStream.Length));
}
// 2. 删除原文件[1,6](@ref)
await minioClient.RemoveObjectAsync(new RemoveObjectArgs()
.WithBucket(minIOConfig.BucketName)
.WithObject(sourcePath));
}
catch (MinioException ex)
{
// 处理异常(例如:记录日志或抛出)
throw new Exception();
}
#endregion
break;
case "AWS":
#region AWS
var awsConfig = ObjectStoreServiceOptions.AWS;
var credentials = new SessionAWSCredentials(
AWSTempToken.AccessKeyId,
AWSTempToken.SecretAccessKey,
AWSTempToken.SessionToken
);
var clientConfig = new AmazonS3Config
{
RegionEndpoint = RegionEndpoint.USEast1,
UseHttp = true,
};
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
// 定义原路径和目标路径
// 1. 复制对象到新路径
var copyRequest = new Amazon.S3.Model.CopyObjectRequest
{
SourceBucket = awsConfig.BucketName,
SourceKey = sourcePath,
DestinationBucket = awsConfig.BucketName,
DestinationKey = destPath
};
try
{
// 执行复制操作
await amazonS3Client.CopyObjectAsync(copyRequest);
// 2. 删除原对象
var deleteRequest = new Amazon.S3.Model.DeleteObjectRequest
{
BucketName = awsConfig.BucketName,
Key = sourcePath
};
await amazonS3Client.DeleteObjectAsync(deleteRequest);
}
catch (AmazonS3Exception ex)
{
Console.WriteLine($"ERROR: {ex.Message}");
// 可根据异常类型细化处理(如文件不存在、权限问题等)
}
#endregion
break;
default:
throw new BusinessValidationFailedException("ERROR");
}
}
/// <summary>
/// 获取所有根目录名称
/// </summary>
/// <returns></returns>
public List<string> GetRootFolderNames()
{
GetObjectStoreTempToken();
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint,
AliyunOSSTempToken.AccessKeyId,
AliyunOSSTempToken.AccessKeySecret,
AliyunOSSTempToken.SecurityToken);
List<string> rootFolders = new List<string>();
string nextMarker = null;
try
{
ObjectListing objectListing = null;
do
{
// 列出根目录下的对象和文件夹
objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(aliConfig.BucketName)
{
MaxKeys = 1000,
Marker = nextMarker,
Delimiter = "/" // 使用分隔符来模拟文件夹
});
// 遍历 CommonPrefixes 获取根文件夹名称
foreach (var prefix in objectListing.CommonPrefixes)
{
rootFolders.Add(prefix.TrimEnd('/')); // 去掉末尾的斜杠
}
// 设置 NextMarker 以获取下一页的数据
nextMarker = objectListing.NextMarker;
} while (objectListing.IsTruncated);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
return rootFolders;
}
/// <summary> /// <summary>
/// 删除某个目录的文件 /// 删除某个目录的文件
/// </summary> /// </summary>
/// <param name="prefix"></param> /// <param name="prefix"></param>
/// <returns></returns> /// <returns></returns>
public async Task DeleteFromPrefix(string prefix) public async Task DeleteFromPrefix(string prefix, bool isCache = false)
{ {
GetObjectStoreTempToken(); GetObjectStoreTempToken();
@ -580,6 +906,21 @@ public class OSSService : IOSSService
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, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
var bucketName = string.Empty;
if (isCache)
{
Uri uri = new Uri(aliConfig.ViewEndpoint);
string host = uri.Host; // 获取 "zy-irc-test-dev-cache.oss-cn-shanghai.aliyuncs.com"
string[] parts = host.Split('.');
bucketName = parts[0];
}
else
{
bucketName = aliConfig.BucketName;
}
try try
{ {
@ -588,7 +929,7 @@ public class OSSService : IOSSService
do do
{ {
// 使用 prefix 模拟目录结构,设置 MaxKeys 和 NextMarker // 使用 prefix 模拟目录结构,设置 MaxKeys 和 NextMarker
objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(aliConfig.BucketName) objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(bucketName)
{ {
Prefix = prefix, Prefix = prefix,
MaxKeys = 1000, MaxKeys = 1000,
@ -600,7 +941,7 @@ public class OSSService : IOSSService
// 删除获取到的文件 // 删除获取到的文件
if (keys.Count > 0) if (keys.Count > 0)
{ {
_ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(aliConfig.BucketName, keys, false)); _ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(bucketName, keys, false));
} }
// 设置 NextMarker 以获取下一页的数据 // 设置 NextMarker 以获取下一页的数据
@ -657,7 +998,6 @@ public class OSSService : IOSSService
var awsConfig = ObjectStoreServiceOptions.AWS; var awsConfig = ObjectStoreServiceOptions.AWS;
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证 // 提供awsAccessKeyId和awsSecretAccessKey构造凭证
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken); var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
@ -709,6 +1049,155 @@ public class OSSService : IOSSService
} }
} }
public async Task DeleteObjects(List<string> objectKeys)
{
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);
if (objectKeys.Count > 0)
{
var result = _ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(aliConfig.BucketName, objectKeys, false));
}
}
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();
if (objectKeys.Count > 0)
{
var objArgs = new RemoveObjectsArgs()
.WithBucket(minIOConfig.BucketName)
.WithObjects(objectKeys);
// 删除对象
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);
if (objectKeys.Count > 0)
{
// 准备删除请求
var deleteObjectsRequest = new Amazon.S3.Model.DeleteObjectsRequest
{
BucketName = awsConfig.BucketName,
Objects = objectKeys.Select(t => new KeyVersion() { Key = t }).ToList()
};
// 批量删除对象
var deleteObjectsResponse = await amazonS3Client.DeleteObjectsAsync(deleteObjectsRequest);
}
}
else
{
throw new BusinessValidationFailedException("未定义的存储介质类型");
}
}
public async Task<long> GetObjectSizeAsync(string sourcePath)
{
BackBatchGetToken();
var objectkey = sourcePath.Trim('/');
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);
var key = HttpUtility.UrlDecode(objectkey);
var metadata = _ossClient.GetObjectMetadata(aliConfig.BucketName, key);
long fileSize = metadata?.ContentLength ?? 0; // 文件大小(字节)
return fileSize;
}
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 stat = await minioClient.StatObjectAsync(new Minio.DataModel.Args.StatObjectArgs()
.WithBucket(minIOConfig.BucketName)
.WithObject(objectkey));
return stat.Size; // 文件大小(字节)
}
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 request = new Amazon.S3.Model.GetObjectMetadataRequest
{
BucketName = awsConfig.BucketName,
Key = objectkey
};
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
var response = await amazonS3Client.GetObjectMetadataAsync(request);
long fileSize = response.ContentLength; // 文件大小(字节)
return fileSize;
}
else
{
throw new BusinessValidationFailedException("未定义的存储介质类型");
}
}
public ObjectStoreDTO GetObjectStoreTempToken() public ObjectStoreDTO GetObjectStoreTempToken()
{ {
@ -752,6 +1241,7 @@ public class OSSService : IOSSService
BucketName = ossOptions.BucketName, BucketName = ossOptions.BucketName,
EndPoint = ossOptions.EndPoint, EndPoint = ossOptions.EndPoint,
ViewEndpoint = ossOptions.ViewEndpoint, ViewEndpoint = ossOptions.ViewEndpoint,
PreviewEndpoint = ossOptions.PreviewEndpoint
}; };

View File

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.Helper
{
public static class SafeBussinessHelper
{
public static async Task<bool> RunAsync(Func<Task> func, [CallerMemberName] string caller = "", string errorMsgTitle = "")
{
try
{
await func();
return true;
}
catch (Exception ex)
{
Log.Logger.Error($"【{errorMsgTitle}失败 - {caller}】: {ex.Message}");
return false;
}
}
public static async Task<(bool Success, T? Result)> RunAsync<T>(Func<Task<T>> func, [CallerMemberName] string caller = "", string errorMsgTitle = "")
{
try
{
var result = await func();
return (true, result);
}
catch (Exception ex)
{
Log.Logger.Error($"【{errorMsgTitle}失败 - {caller}】: {ex.Message}");
return (false, default);
}
}
}
}

View File

@ -34,36 +34,37 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="MaxMind.GeoIP2" Version="5.3.0" /> <PackageReference Include="MaxMind.GeoIP2" Version="5.3.0" />
<PackageReference Include="IdentityModel.OidcClient" Version="6.0.0" /> <PackageReference Include="IdentityModel.OidcClient" Version="6.0.0" />
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.4" /> <PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.6" />
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.400.36" /> <PackageReference Include="AWSSDK.SecurityToken" Version="4.0.2" />
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" /> <PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
<PackageReference Include="AWSSDK.S3" Version="3.7.405" /> <PackageReference Include="AWSSDK.S3" Version="4.0.6.8" />
<PackageReference Include="DocX" Version="3.0.1" /> <PackageReference Include="DocX" Version="4.0.25105.5786" />
<PackageReference Include="FreeSpire.Doc" Version="12.2.0" /> <PackageReference Include="FreeSpire.Doc" Version="12.2.0" />
<PackageReference Include="ExcelDataReader" Version="3.7.0" /> <PackageReference Include="ExcelDataReader" Version="3.7.0" />
<PackageReference Include="ExcelDataReader.DataSet" Version="3.7.0" /> <PackageReference Include="ExcelDataReader.DataSet" Version="3.7.0" />
<PackageReference Include="DistributedLock.Redis" Version="1.0.3" /> <PackageReference Include="DistributedLock.Redis" Version="1.1.0" />
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.5" /> <PackageReference Include="DistributedLock.SqlServer" Version="1.0.6" />
<PackageReference Include="fo-dicom" Version="5.1.3" /> <PackageReference Include="fo-dicom" Version="5.2.2" />
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.1.3" /> <PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.2" />
<PackageReference Include="fo-dicom.Codecs" Version="5.15.1" /> <PackageReference Include="fo-dicom.Codecs" Version="5.16.4" />
<PackageReference Include="IP2Region.Net" Version="2.0.2" /> <PackageReference Include="IP2Region.Net" Version="2.0.2" />
<PackageReference Include="MailKit" Version="4.7.1.1" /> <PackageReference Include="MailKit" Version="4.13.0" />
<PackageReference Include="Masa.Contrib.Service.MinimalAPIs" Version="1.0.0" /> <PackageReference Include="Masa.Contrib.Service.MinimalAPIs" Version="1.0.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" />
<PackageReference Include="MimeKit" Version="4.7.1" /> <PackageReference Include="MimeKit" Version="4.13.0" />
<PackageReference Include="MiniExcel" Version="1.34.2" /> <PackageReference Include="MiniExcel" Version="1.41.3" />
<PackageReference Include="Minio" Version="6.0.3" /> <PackageReference Include="Minio" Version="6.0.5" />
<PackageReference Include="MiniWord" Version="0.9.2" /> <PackageReference Include="MiniWord" Version="0.9.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="NPOI" Version="2.7.1" /> <PackageReference Include="NPOI" Version="2.7.4" />
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" /> <PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
<PackageReference Include="RestSharp" Version="112.1.0" /> <PackageReference Include="RestSharp" Version="112.1.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.5" /> <PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="9.0.0" /> <PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="9.0.0" />
<PackageReference Include="ZiggyCreatures.FusionCache" Version="1.4.0" /> <PackageReference Include="ZiggyCreatures.FusionCache" Version="2.4.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -13870,7 +13870,21 @@
<returns></returns> <returns></returns>
<exception cref="T:IRaCIS.Core.Infrastructure.BusinessValidationFailedException"></exception> <exception cref="T:IRaCIS.Core.Infrastructure.BusinessValidationFailedException"></exception>
</member> </member>
<member name="M:IRaCIS.Core.Application.Helper.OSSService.DeleteFromPrefix(System.String)"> <member name="M:IRaCIS.Core.Application.Helper.OSSService.MoveObject(System.String,System.String,System.Boolean)">
<summary>
移动OSS文件到新路径
</summary>
<param name="sourcePath">原文件路径格式bucket/key</param>
<param name="destPath">新文件路径格式bucket/key</param>
<param name="overwrite">是否覆盖已存在的目标文件默认true</param>
</member>
<member name="M:IRaCIS.Core.Application.Helper.OSSService.GetRootFolderNames">
<summary>
获取所有根目录名称
</summary>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Helper.OSSService.DeleteFromPrefix(System.String,System.Boolean)">
<summary> <summary>
删除某个目录的文件 删除某个目录的文件
</summary> </summary>
@ -18408,7 +18422,7 @@
<param name="inQuery"></param> <param name="inQuery"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:IRaCIS.Application.Services.PatientService.GetDownloadSubjectVisitStudyInfo(System.Guid,System.Guid)"> <member name="M:IRaCIS.Application.Services.PatientService.GetDownloadSubjectVisitStudyInfo(System.Guid,System.Guid,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomStudy},IRaCIS.Core.Application.Helper.IOSSService)">
<summary> <summary>
获取下载的访视检查信息 获取下载的访视检查信息
</summary> </summary>

View File

@ -1148,4 +1148,31 @@ namespace IRaCIS.Application.Contracts
} }
public class DownloadDicomStudyDto
{
public string PatientId { get; set; }
public DateTime? StudyTime { get; set; }
public string StudyCode { get; set; }
public string StudyInstanceUid { get; set; }
public string StudyDIRPath { get; set; }
public List<DownloadDicomSeriesDto> SeriesList { get; set; }
}
public class DownloadDicomSeriesDto
{
public string Modality { get; set; }
public List<DownloadDicomInstanceDto> InstanceList { get; set; }
}
public class DownloadDicomInstanceDto
{
public bool IsEncapsulated { get; set; }
public Guid InstanceId { get; set; }
public string FileName { get; set; }
public string Path { get; set; }
public long? FileSize { get; set; }
}
} }

View File

@ -27,7 +27,6 @@ using MailKit.Search;
using DocumentFormat.OpenXml.Office2010.Excel; using DocumentFormat.OpenXml.Office2010.Excel;
using IRaCIS.Core.Application.Contracts.Dicom.DTO; using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using IRaCIS.Core.Application.Helper; using IRaCIS.Core.Application.Helper;
using NPOI.SS.Formula.Functions;
using System.Linq; using System.Linq;
using System.Linq.Dynamic.Core; using System.Linq.Dynamic.Core;
using System.Text; using System.Text;
@ -36,7 +35,6 @@ using Azure;
using System.IO.Compression; using System.IO.Compression;
using static IRaCIS.Core.Domain.Share.StaticData; using static IRaCIS.Core.Domain.Share.StaticData;
using FellowOakDicom; using FellowOakDicom;
using DocumentFormat.OpenXml.Office2010.Drawing;
using IDistributedLockProvider = Medallion.Threading.IDistributedLockProvider; using IDistributedLockProvider = Medallion.Threading.IDistributedLockProvider;
using DocumentFormat.OpenXml.InkML; using DocumentFormat.OpenXml.InkML;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
@ -46,16 +44,11 @@ using FellowOakDicom.Network;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using DocumentFormat.OpenXml.Wordprocessing; using DocumentFormat.OpenXml.Wordprocessing;
using System; using System;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
using DocumentFormat.OpenXml.Vml.Office;
using IRaCIS.Core.Infra.EFCore.Migrations; using IRaCIS.Core.Infra.EFCore.Migrations;
using System.Dynamic; using System.Dynamic;
using System.Threading.Channels; using System.Threading.Channels;
using NPOI.HSSF.Record.Chart;
using IRaCIS.Core.Application.Helper.OtherTool; using IRaCIS.Core.Application.Helper.OtherTool;
using IRaCIS.Core.Infrastructure.Extention; using IRaCIS.Core.Infrastructure.Extention;
using DocumentFormat.OpenXml.Drawing.Charts;
using DocumentFormat.OpenXml.Drawing.Diagrams;
namespace IRaCIS.Application.Services namespace IRaCIS.Application.Services
@ -2931,8 +2924,73 @@ namespace IRaCIS.Application.Services
/// <param name="trialId"></param> /// <param name="trialId"></param>
/// <param name="subjectVisitId"></param> /// <param name="subjectVisitId"></param>
/// <returns></returns> /// <returns></returns>
public async Task<IResponseOutput> GetDownloadSubjectVisitStudyInfo(Guid trialId, Guid subjectVisitId) public async Task<IResponseOutput> GetDownloadSubjectVisitStudyInfo(Guid trialId, Guid subjectVisitId,
[FromServices] IRepository<DicomStudy> _dicomStudyRepository, [FromServices] IOSSService _oSSService)
{ {
var dirDic = new Dictionary<string, string>();
#region DIR处理导出文件名并将对应关系上传到OSS里面存储
//有传输语法值的导出 才生成DIR
if (_subjectVisitRepository.Where(t => t.Id == subjectVisitId).SelectMany(t => t.StudyList.SelectMany(t => t.InstanceList)).All(c => c.TransferSyntaxUID != string.Empty))
{
var list = _subjectVisitRepository.Where(t => t.Id == subjectVisitId).SelectMany(t => t.StudyList)
.SelectMany(t => t.InstanceList)
.Select(t => new StudyDIRInfo()
{
DicomStudyId = t.DicomStudy.Id,
PatientId = t.DicomStudy.PatientId,
PatientName = t.DicomStudy.PatientName,
PatientBirthDate = t.DicomStudy.PatientBirthDate,
PatientSex = t.DicomStudy.PatientSex,
StudyInstanceUid = t.StudyInstanceUid,
StudyId = t.DicomStudy.StudyId,
DicomStudyDate = t.DicomStudy.DicomStudyDate,
DicomStudyTime = t.DicomStudy.DicomStudyTime,
AccessionNumber = t.DicomStudy.AccessionNumber,
StudyDescription = t.DicomStudy.Description,
SeriesInstanceUid = t.DicomSerie.SeriesInstanceUid,
Modality = t.DicomSerie.Modality,
DicomSeriesDate = t.DicomSerie.DicomSeriesDate,
DicomSeriesTime = t.DicomSerie.DicomSeriesTime,
SeriesNumber = t.DicomSerie.SeriesNumber,
SeriesDescription = t.DicomSerie.Description,
InstanceId = t.Id,
SopInstanceUid = t.SopInstanceUid,
SOPClassUID = t.SOPClassUID,
InstanceNumber = t.InstanceNumber,
MediaStorageSOPClassUID = t.MediaStorageSOPClassUID,
MediaStorageSOPInstanceUID = t.MediaStorageSOPInstanceUID,
TransferSyntaxUID = t.TransferSyntaxUID,
}).ToList();
var pathInfo = await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).Select(t => new { t.TrialId, t.SubjectId, VisitId = t.Id }).FirstNotNullAsync();
foreach (var item in list.GroupBy(t => new { t.StudyInstanceUid, t.DicomStudyId }))
{
var ossFolder = $"{pathInfo.TrialId}/Image/{pathInfo.SubjectId}/{pathInfo.VisitId}/{item.Key.StudyInstanceUid}";
var isSucess = await SafeBussinessHelper.RunAsync(async () => await DicomDIRHelper.GenerateStudyDIRAndUploadAsync(item.ToList(), dirDic, ossFolder, _oSSService));
if (isSucess)
{
await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/DICOMDIR" });
}
}
}
#endregion
var query = from sv in _subjectVisitRepository.Where(t => t.Id == subjectVisitId) var query = from sv in _subjectVisitRepository.Where(t => t.Id == subjectVisitId)
select new select new
@ -2943,23 +3001,27 @@ namespace IRaCIS.Application.Services
VisitName = sv.VisitName, VisitName = sv.VisitName,
StudyList = sv.StudyList StudyList = sv.StudyList
.Select(u => new DownloadDicomStudyDto()
.Select(u => new
{ {
u.PatientIdStr, PatientId = u.PatientIdStr,
u.StudyTime, StudyTime = u.StudyTime,
u.StudyCode, StudyCode = u.StudyCode,
StudyInstanceUid = u.StudyInstanceUid,
StudyDIRPath = u.StudyDIRPath,
SeriesList = u.SeriesList.Select(z => new SeriesList = u.SeriesList.Select(z => new DownloadDicomSeriesDto()
{ {
z.Modality, Modality = z.Modality,
InstanceList = z.DicomInstanceList.Select(k => new InstanceList = z.DicomInstanceList.Select(k => new DownloadDicomInstanceDto()
{ {
k.Path, IsEncapsulated = k.IsEncapsulated,
k.FileSize InstanceId = k.Id,
}) FileName = string.Empty,
}) Path = k.Path,
FileSize = k.FileSize
}).ToList()
}).ToList()
}).ToList(), }).ToList(),
@ -2968,6 +3030,15 @@ namespace IRaCIS.Application.Services
var result = query.FirstOrDefault(); var result = query.FirstOrDefault();
foreach (var item in result.StudyList.SelectMany(t => t.SeriesList).SelectMany(t => t.InstanceList))
{
var key = item.InstanceId.ToString();
if (dirDic.ContainsKey(key))
{
item.FileName = dirDic[key];
}
}
var preDownloadInfo = new SubejctVisitDownload() var preDownloadInfo = new SubejctVisitDownload()
{ {
Id = NewId.NextSequentialGuid(), Id = NewId.NextSequentialGuid(),
@ -3119,13 +3190,12 @@ namespace IRaCIS.Application.Services
return request; return request;
} }
public static void DebugStudyResponse(DicomCFindResponse response, ILogger _logger) public static void DebugStudyResponse(DicomCFindResponse response)
{ {
if (response.Status == DicomStatus.Pending) if (response.Status == DicomStatus.Pending)
{ {
// print the results // print the results
_logger.LogDebug($"Patient {response.Dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty)}, {(response.Dataset.TryGetString(DicomTag.ModalitiesInStudy, out var dummy) ? dummy : string.Empty)}-Study from {response.Dataset.GetSingleValueOrDefault(DicomTag.StudyDate, new DateTime())} with UID {response.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty)} "); Log.Logger.Debug($"Patient {response.Dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty)}, {(response.Dataset.TryGetString(DicomTag.ModalitiesInStudy, out var dummy) ? dummy : string.Empty)}-Study from {response.Dataset.GetSingleValueOrDefault(DicomTag.StudyDate, new DateTime())} with UID {response.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty)} ");
} }
if (response.Status == DicomStatus.Success) if (response.Status == DicomStatus.Success)
{ {

View File

@ -75,4 +75,20 @@ public class DicomInstance : BaseFullAuditEntity, IEntitySeqId
public string WindowWidth { get; set; } = null!; public string WindowWidth { get; set; } = null!;
#region DIR 增加
public string SOPClassUID { get; set; }
public string MediaStorageSOPClassUID { get; set; }
public string TransferSyntaxUID { get; set; }
public string MediaStorageSOPInstanceUID { get; set; }
public bool IsEncapsulated { get; set; }
#endregion
} }

View File

@ -68,5 +68,13 @@ public class DicomSeries : BaseFullDeleteAuditEntity, IEntitySeqId
public string TriggerTime { get; set; } = null!; public string TriggerTime { get; set; } = null!;
public Guid? VisitTaskId { get; set; } public Guid? VisitTaskId { get; set; }
#region DIR 增加
public string DicomSeriesDate { get; set; }
public string DicomSeriesTime { get; set; }
#endregion
} }

View File

@ -10,6 +10,9 @@ public class DicomStudy : BaseFullDeleteAuditEntity, IEntitySeqId
[JsonIgnore] [JsonIgnore]
public List<DicomSeries> SeriesList { get; set; } public List<DicomSeries> SeriesList { get; set; }
[JsonIgnore]
public List<DicomInstance> InstanceList { get; set; }
[JsonIgnore] [JsonIgnore]
[ForeignKey("SubjectId")] [ForeignKey("SubjectId")]
public Subject Subject { get; set; } public Subject Subject { get; set; }
@ -95,4 +98,15 @@ public class DicomStudy : BaseFullDeleteAuditEntity, IEntitySeqId
public string PatientIdStr { get; set; } = string.Empty; public string PatientIdStr { get; set; } = string.Empty;
#region DIR 增加字段
public string DicomStudyDate { get; set; }
public string DicomStudyTime { get; set; }
public string StudyDIRPath { get; set; }
#endregion
} }

View File

@ -40,4 +40,19 @@ public class SCPInstance : BaseFullAuditEntity, IEntitySeqId
public string Path { get; set; } = string.Empty; public string Path { get; set; } = string.Empty;
public long? FileSize { get; set; } public long? FileSize { get; set; }
#region DIR 增加
public string SOPClassUID { get; set; }
public string MediaStorageSOPClassUID { get; set; }
public string TransferSyntaxUID { get; set; }
public string MediaStorageSOPInstanceUID { get; set; }
public bool IsEncapsulated { get; set; }
#endregion
} }

View File

@ -39,4 +39,12 @@ public class SCPSeries : BaseFullDeleteAuditEntity, IEntitySeqId
[StringLength(1000)] [StringLength(1000)]
public string ImageResizePath { get; set; } = string.Empty; public string ImageResizePath { get; set; } = string.Empty;
#region DIR 增加
public string DicomSeriesDate { get; set; }
public string DicomSeriesTime { get; set; }
#endregion
} }

View File

@ -75,6 +75,16 @@ public class SCPStudy : BaseFullDeleteAuditEntity, IEntitySeqId
//public Guid? SubjectVisitId { get; set; } //public Guid? SubjectVisitId { get; set; }
#endregion #endregion
#region DIR 增加字段
public string DicomStudyDate { get; set; }
public string DicomStudyTime { get; set; }
public string StudyDIRPath { get; set; }
#endregion
} }
public class SCPStudyHospitalGroup : BaseFullAuditEntity public class SCPStudyHospitalGroup : BaseFullAuditEntity

View File

@ -13,6 +13,8 @@ public class DicomStudyConfigration : IEntityTypeConfiguration<DicomStudy>
{ {
builder.HasKey(e => e.SeqId); builder.HasKey(e => e.SeqId);
builder.HasMany(s => s.InstanceList).WithOne(se => se.DicomStudy).HasForeignKey(se => se.StudyId).HasPrincipalKey(st => st.Id);
builder.HasMany(s => s.SeriesList).WithOne(se => se.DicomStudy).HasForeignKey(se => se.StudyId).HasPrincipalKey(st => st.Id); builder.HasMany(s => s.SeriesList).WithOne(se => se.DicomStudy).HasForeignKey(se => se.StudyId).HasPrincipalKey(st => st.Id);
builder.HasMany(s => s.DicomStudyMonitorList).WithOne(sm => sm.DicomStudy).HasForeignKey(sm => sm.StudyId).HasPrincipalKey(se => se.Id); builder.HasMany(s => s.DicomStudyMonitorList).WithOne(sm => sm.DicomStudy).HasForeignKey(sm => sm.StudyId).HasPrincipalKey(se => se.Id);
@ -40,7 +42,7 @@ public class DicomInstanceConfigration : IEntityTypeConfiguration<DicomInstance>
{ {
builder.HasKey(e => e.SeqId); builder.HasKey(e => e.SeqId);
builder.HasOne(e => e.DicomStudy).WithMany().HasForeignKey(t => t.StudyId).HasPrincipalKey(st => st.Id); builder.HasOne(e => e.DicomStudy).WithMany(c => c.InstanceList).HasForeignKey(t => t.StudyId).HasPrincipalKey(st => st.Id);
builder.HasMany(s => s.ReadingTableAnswerRowInfoList).WithOne(di => di.Instance).HasForeignKey(t => t.InstanceId).HasPrincipalKey(se => se.Id); builder.HasMany(s => s.ReadingTableAnswerRowInfoList).WithOne(di => di.Instance).HasForeignKey(t => t.InstanceId).HasPrincipalKey(se => se.Id);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,256 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace IRaCIS.Core.Infra.EFCore.Migrations
{
/// <inheritdoc />
public partial class dicomDir : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "DicomStudyDate",
table: "SCPStudy",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "DicomStudyTime",
table: "SCPStudy",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "StudyDIRPath",
table: "SCPStudy",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "DicomSeriesDate",
table: "SCPSeries",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "DicomSeriesTime",
table: "SCPSeries",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<bool>(
name: "IsEncapsulated",
table: "SCPInstance",
type: "bit",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<string>(
name: "MediaStorageSOPClassUID",
table: "SCPInstance",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "MediaStorageSOPInstanceUID",
table: "SCPInstance",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "SOPClassUID",
table: "SCPInstance",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "TransferSyntaxUID",
table: "SCPInstance",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "DicomStudyDate",
table: "DicomStudy",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "DicomStudyTime",
table: "DicomStudy",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "StudyDIRPath",
table: "DicomStudy",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "DicomSeriesDate",
table: "DicomSeries",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "DicomSeriesTime",
table: "DicomSeries",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<bool>(
name: "IsEncapsulated",
table: "DicomInstance",
type: "bit",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<string>(
name: "MediaStorageSOPClassUID",
table: "DicomInstance",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "MediaStorageSOPInstanceUID",
table: "DicomInstance",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "SOPClassUID",
table: "DicomInstance",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "TransferSyntaxUID",
table: "DicomInstance",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "DicomStudyDate",
table: "SCPStudy");
migrationBuilder.DropColumn(
name: "DicomStudyTime",
table: "SCPStudy");
migrationBuilder.DropColumn(
name: "StudyDIRPath",
table: "SCPStudy");
migrationBuilder.DropColumn(
name: "DicomSeriesDate",
table: "SCPSeries");
migrationBuilder.DropColumn(
name: "DicomSeriesTime",
table: "SCPSeries");
migrationBuilder.DropColumn(
name: "IsEncapsulated",
table: "SCPInstance");
migrationBuilder.DropColumn(
name: "MediaStorageSOPClassUID",
table: "SCPInstance");
migrationBuilder.DropColumn(
name: "MediaStorageSOPInstanceUID",
table: "SCPInstance");
migrationBuilder.DropColumn(
name: "SOPClassUID",
table: "SCPInstance");
migrationBuilder.DropColumn(
name: "TransferSyntaxUID",
table: "SCPInstance");
migrationBuilder.DropColumn(
name: "DicomStudyDate",
table: "DicomStudy");
migrationBuilder.DropColumn(
name: "DicomStudyTime",
table: "DicomStudy");
migrationBuilder.DropColumn(
name: "StudyDIRPath",
table: "DicomStudy");
migrationBuilder.DropColumn(
name: "DicomSeriesDate",
table: "DicomSeries");
migrationBuilder.DropColumn(
name: "DicomSeriesTime",
table: "DicomSeries");
migrationBuilder.DropColumn(
name: "IsEncapsulated",
table: "DicomInstance");
migrationBuilder.DropColumn(
name: "MediaStorageSOPClassUID",
table: "DicomInstance");
migrationBuilder.DropColumn(
name: "MediaStorageSOPInstanceUID",
table: "DicomInstance");
migrationBuilder.DropColumn(
name: "SOPClassUID",
table: "DicomInstance");
migrationBuilder.DropColumn(
name: "TransferSyntaxUID",
table: "DicomInstance");
}
}
}

View File

@ -936,6 +936,19 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
b.Property<DateTime?>("InstanceTime") b.Property<DateTime?>("InstanceTime")
.HasColumnType("datetime2"); .HasColumnType("datetime2");
b.Property<bool>("IsEncapsulated")
.HasColumnType("bit");
b.Property<string>("MediaStorageSOPClassUID")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<string>("MediaStorageSOPInstanceUID")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<int>("NumberOfFrames") b.Property<int>("NumberOfFrames")
.HasColumnType("int"); .HasColumnType("int");
@ -949,6 +962,11 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
.HasMaxLength(400) .HasMaxLength(400)
.HasColumnType("nvarchar(400)"); .HasColumnType("nvarchar(400)");
b.Property<string>("SOPClassUID")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<Guid>("SeriesId") b.Property<Guid>("SeriesId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
@ -984,6 +1002,11 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
b.Property<Guid>("SubjectVisitId") b.Property<Guid>("SubjectVisitId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("TransferSyntaxUID")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<Guid>("TrialId") b.Property<Guid>("TrialId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
@ -1060,6 +1083,16 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
.HasMaxLength(400) .HasMaxLength(400)
.HasColumnType("nvarchar(400)"); .HasColumnType("nvarchar(400)");
b.Property<string>("DicomSeriesDate")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<string>("DicomSeriesTime")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
@ -1218,6 +1251,16 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
.HasMaxLength(400) .HasMaxLength(400)
.HasColumnType("nvarchar(400)"); .HasColumnType("nvarchar(400)");
b.Property<string>("DicomStudyDate")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<string>("DicomStudyTime")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
@ -1287,6 +1330,11 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
.HasMaxLength(400) .HasMaxLength(400)
.HasColumnType("nvarchar(400)"); .HasColumnType("nvarchar(400)");
b.Property<string>("StudyDIRPath")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<string>("StudyId") b.Property<string>("StudyId")
.IsRequired() .IsRequired()
.HasMaxLength(400) .HasMaxLength(400)
@ -7675,6 +7723,19 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
b.Property<DateTime?>("InstanceTime") b.Property<DateTime?>("InstanceTime")
.HasColumnType("datetime2"); .HasColumnType("datetime2");
b.Property<bool>("IsEncapsulated")
.HasColumnType("bit");
b.Property<string>("MediaStorageSOPClassUID")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<string>("MediaStorageSOPInstanceUID")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<int>("NumberOfFrames") b.Property<int>("NumberOfFrames")
.HasColumnType("int"); .HasColumnType("int");
@ -7688,6 +7749,11 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
.HasMaxLength(400) .HasMaxLength(400)
.HasColumnType("nvarchar(400)"); .HasColumnType("nvarchar(400)");
b.Property<string>("SOPClassUID")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<Guid>("SeriesId") b.Property<Guid>("SeriesId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
@ -7717,6 +7783,11 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
.HasMaxLength(400) .HasMaxLength(400)
.HasColumnType("nvarchar(400)"); .HasColumnType("nvarchar(400)");
b.Property<string>("TransferSyntaxUID")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<DateTime>("UpdateTime") b.Property<DateTime>("UpdateTime")
.HasColumnType("datetime2"); .HasColumnType("datetime2");
@ -7851,6 +7922,16 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
.HasMaxLength(400) .HasMaxLength(400)
.HasColumnType("nvarchar(400)"); .HasColumnType("nvarchar(400)");
b.Property<string>("DicomSeriesDate")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<string>("DicomSeriesTime")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
@ -8000,6 +8081,16 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
.HasMaxLength(400) .HasMaxLength(400)
.HasColumnType("nvarchar(400)"); .HasColumnType("nvarchar(400)");
b.Property<string>("DicomStudyDate")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<string>("DicomStudyTime")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
@ -8058,6 +8149,11 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
b.Property<int>("SeriesCount") b.Property<int>("SeriesCount")
.HasColumnType("int"); .HasColumnType("int");
b.Property<string>("StudyDIRPath")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<string>("StudyId") b.Property<string>("StudyId")
.IsRequired() .IsRequired()
.HasMaxLength(400) .HasMaxLength(400)
@ -14699,7 +14795,7 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
.IsRequired(); .IsRequired();
b.HasOne("IRaCIS.Core.Domain.Models.DicomStudy", "DicomStudy") b.HasOne("IRaCIS.Core.Domain.Models.DicomStudy", "DicomStudy")
.WithMany() .WithMany("InstanceList")
.HasForeignKey("StudyId") .HasForeignKey("StudyId")
.HasPrincipalKey("Id") .HasPrincipalKey("Id")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
@ -18493,6 +18589,8 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
{ {
b.Navigation("DicomStudyMonitorList"); b.Navigation("DicomStudyMonitorList");
b.Navigation("InstanceList");
b.Navigation("ReadingClinicalDataList"); b.Navigation("ReadingClinicalDataList");
b.Navigation("ReadingConsistentClinicalDataList"); b.Navigation("ReadingConsistentClinicalDataList");

View File

@ -18,7 +18,7 @@
<PackageReference Include="SharpCompress" Version="0.38.0" /> <PackageReference Include="SharpCompress" Version="0.38.0" />
<PackageReference Include="SharpZipLib" Version="1.4.2" /> <PackageReference Include="SharpZipLib" Version="1.4.2" />
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" /> <PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.4.6" /> <PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.7" />
</ItemGroup> </ItemGroup>