Organizacje opieki zdrowotnej coraz bardziej potrzebują automatycznych rozwiązań do de-identyfikacji danych obrazów medycznych.W tym przewodniku dowiesz się, jak zbudować DICOM anonimowość microservice w ASP.NET Core, który otrzymuje pliki DICUM za pośrednictwem HTTP, anonymializuje je za pomocą konfigurowalnych profili, i zwraca deidentified wyniki.
Tabela zawartości
- Przegląd architektury
- Ustawienie projektu
- Wdrażanie warstwy obsługi
- Tworzenie kontrolera API
- Konfigurowane profily
- Rozważania bezpieczeństwa
- Optymalizacja wydajności
- konkluzja
Przegląd architektury
Mikroservice śledzi warstwę architektury z wyraźnym oddzieleniem obaw. warstwa API obsługuje zapytania HTTP i odpowiedzi za pośrednictwem kontrolerów ASP.NET Core. Warstwa obsługi zawiera logikę biznesową za pomocą Aspose.Medical Anonymizer. Ścieżka konfiguracji zarządza ustawieniami profilu i opcjami aplikacji. Opcjonalne komponenty obejmują przechowywanie do logowania i kwing dla przetwarzania partii.
Ta architektura umożliwia skalowanie horyzontalne, łatwe testowanie i prostą integrację z systemami informacyjnymi szpitala i serwerami PACS.
Ustawienie projektu
Zacznij tworząc nowy projekt ASP.NET Core Web API i zainstaluj wymagany pakiet:
dotnet new webapi -n DicomAnonymizationService
cd DicomAnonymizationService
dotnet add package Aspose.Medical
Konfiguruj projekt dla dużych przesyłek plików Program.cs:
var builder = WebApplication.CreateBuilder(args);
// Configure for large DICOM files
builder.WebHost.ConfigureKestrel(options =>
{
options.Limits.MaxRequestBodySize = 500_000_000; // 500MB
});
builder.Services.Configure<FormOptions>(options =>
{
options.MultipartBodyLengthLimit = 500_000_000;
});
// Register services
builder.Services.AddScoped<IDicomAnonymizationService, DicomAnonymizationService>();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
Wdrażanie warstwy serwisowej
Tworzenie interfejsu i wdrożenie usługi anonimowości:
using Aspose.Medical.Dicom;
using Aspose.Medical.Dicom.Anonymization;
public interface IDicomAnonymizationService
{
Task<byte[]> AnonymizeAsync(Stream inputStream, string? profileName = null);
Task<byte[]> AnonymizeAsync(byte[] inputBytes, string? profileName = null);
}
public class DicomAnonymizationService : IDicomAnonymizationService
{
private readonly ILogger<DicomAnonymizationService> _logger;
private readonly Dictionary<string, ConfidentialityProfileOptions> _profiles;
public DicomAnonymizationService(ILogger<DicomAnonymizationService> logger)
{
_logger = logger;
_profiles = new Dictionary<string, ConfidentialityProfileOptions>
{
["basic"] = ConfidentialityProfileOptions.BasicProfile,
["research"] = ConfidentialityProfileOptions.BasicProfile |
ConfidentialityProfileOptions.RetainPatientChars,
["internal"] = ConfidentialityProfileOptions.RetainUIDs |
ConfidentialityProfileOptions.RetainDeviceIdent,
["clean"] = ConfidentialityProfileOptions.CleanGraph |
ConfidentialityProfileOptions.CleanDesc
};
}
public async Task<byte[]> AnonymizeAsync(Stream inputStream, string? profileName = null)
{
using var memoryStream = new MemoryStream();
await inputStream.CopyToAsync(memoryStream);
return await AnonymizeAsync(memoryStream.ToArray(), profileName);
}
public Task<byte[]> AnonymizeAsync(byte[] inputBytes, string? profileName = null)
{
return Task.Run(() =>
{
// Create anonymizer with selected profile
Anonymizer anonymizer = CreateAnonymizer(profileName);
// Load DICOM from bytes
using var inputStream = new MemoryStream(inputBytes);
DicomFile dcm = DicomFile.Open(inputStream);
// Anonymize
DicomFile anonymizedDcm = anonymizer.Anonymize(dcm);
// Write to output stream
using var outputStream = new MemoryStream();
anonymizedDcm.Save(outputStream);
_logger.LogInformation("Anonymized DICOM file using profile: {Profile}",
profileName ?? "default");
return outputStream.ToArray();
});
}
private Anonymizer CreateAnonymizer(string? profileName)
{
if (string.IsNullOrEmpty(profileName) || !_profiles.ContainsKey(profileName.ToLower()))
{
return new Anonymizer();
}
var options = _profiles[profileName.ToLower()];
var profile = ConfidentialityProfile.CreateDefault(options);
return new Anonymizer(profile);
}
}
Tworzenie kontrolera API
Tworzenie sterownika, który obsługuje przesyłki plików i zwraca anonimowe pliki DICOM:
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class AnonymizeController : ControllerBase
{
private readonly IDicomAnonymizationService _anonymizationService;
private readonly ILogger<AnonymizeController> _logger;
public AnonymizeController(
IDicomAnonymizationService anonymizationService,
ILogger<AnonymizeController> logger)
{
_anonymizationService = anonymizationService;
_logger = logger;
}
/// <summary>
/// Anonymize a single DICOM file
/// </summary>
[HttpPost]
[RequestSizeLimit(500_000_000)]
public async Task<IActionResult> AnonymizeFile(
IFormFile file,
[FromQuery] string? profile = null)
{
if (file == null || file.Length == 0)
{
return BadRequest("No file uploaded");
}
try
{
_logger.LogInformation("Processing file: {FileName}, Size: {Size}",
file.FileName, file.Length);
using var stream = file.OpenReadStream();
byte[] anonymizedBytes = await _anonymizationService.AnonymizeAsync(stream, profile);
string outputFileName = $"anonymized_{file.FileName}";
return File(anonymizedBytes, "application/dicom", outputFileName);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error anonymizing file: {FileName}", file.FileName);
return StatusCode(500, $"Anonymization failed: {ex.Message}");
}
}
/// <summary>
/// Anonymize DICOM data from request body
/// </summary>
[HttpPost("stream")]
[RequestSizeLimit(500_000_000)]
public async Task<IActionResult> AnonymizeStream([FromQuery] string? profile = null)
{
try
{
byte[] anonymizedBytes = await _anonymizationService.AnonymizeAsync(
Request.Body, profile);
return File(anonymizedBytes, "application/dicom", "anonymized.dcm");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error anonymizing stream");
return StatusCode(500, $"Anonymization failed: {ex.Message}");
}
}
/// <summary>
/// List available anonymization profiles
/// </summary>
[HttpGet("profiles")]
public IActionResult GetProfiles()
{
var profiles = new[]
{
new { name = "basic", description = "Standard anonymization removing most identifiers" },
new { name = "research", description = "Retains patient characteristics for research" },
new { name = "internal", description = "Retains UIDs for internal tracking" },
new { name = "clean", description = "Removes burned-in graphics and descriptions" }
};
return Ok(profiles);
}
}
Konfigurowane profily
Umożliwia konfigurowanie profili poprzez appsettings.json:
{
"AnonymizationProfiles": {
"default": "basic",
"profiles": {
"basic": ["BasicProfile"],
"research": ["BasicProfile", "RetainPatientChars"],
"internal": ["RetainUIDs", "RetainDeviceIdent"],
"clean": ["CleanGraph", "CleanDesc"],
"maximum": ["BasicProfile", "CleanGraph", "CleanDesc"]
}
}
}
Tworzyć klasę konfiguracji i zaktualizować usługę do odczytu z ustawień:
public class AnonymizationProfileOptions
{
public string Default { get; set; } = "basic";
public Dictionary<string, string[]> Profiles { get; set; } = new();
}
// In Program.cs
builder.Services.Configure<AnonymizationProfileOptions>(
builder.Configuration.GetSection("AnonymizationProfiles"));
Rozważania dotyczące bezpieczeństwa
Podczas korzystania z tej usługi wdrażamy te środki bezpieczeństwa.
Umożliwia HTTPS, aby upewnić się, że wszystkie komunikacje są szyfrowane w czasie tranzytu. skonfigurować TLS 1.2 lub wyższy i przekierować Http do https.
Wdrożenie uwierzytelniania za pomocą tokenów JWT lub kluczy API w celu ograniczenia dostępu do upoważnionych klientów:
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class AnonymizeController : ControllerBase
{
// Controller code...
}
** Unikaj przechowywania oryginalnych plików** bez szyfrowania na dysku. przetwarzanie pliki w pamięci, gdy jest to możliwe, a jeśli potrzebne jest tymczasowe zapisywanie, użyj zaszyfrowanych objętości.
Umożliwia rejestrację audytu do śledzenia wszystkich operacji anonimowości, w tym tych, którzy ich poprosili i kiedy:
_logger.LogInformation(
"Anonymization completed - User: {User}, Profile: {Profile}, FileSize: {Size}",
User.Identity?.Name, profile, file.Length);
Optymalizacja wydajności
Kilka technik może poprawić wydajność dla scenariuszy o wysokiej mocy.
Użyj anonimowości w miejscu, gdy nie musisz przechowywać oryginalnych danych w pamięci:
anonymizer.AnonymizeInPlace(dcm);
Umożliwia równoległe przetwarzanie dla operacji zbiornika:
[HttpPost("batch")]
public async Task<IActionResult> AnonymizeBatch(List<IFormFile> files)
{
var results = await Parallel.ForEachAsync(
files,
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
async (file, ct) =>
{
using var stream = file.OpenReadStream();
return await _anonymizationService.AnonymizeAsync(stream);
});
// Return results...
}
Wdrożenie żądania kwing dla bardzo dużych partii za pomocą kwingu wiadomości, takich jak RabbitMQ lub Azure Service Bus do obsługi spików ładowania bez przesadzenia usługi.
Konkluzja
Teraz masz kompletny plakat do budowy DICOM anonimizacji microservice w ASP.NET Core. Usługa akceptuje pliki DICUM za pośrednictwem HTTP, stosuje konfigurowalne profily anonimizacji za pomocą Aspose.Medical i zwraca de-identyfikowane pliky gotowe do badań lub udostępniania.
Kluczowe zadania obejmują wykorzystanie warstwy architektury w celu utrzymania, wdrażanie konfigurowalnych profilów dla elastyczności, zapewnienie usługi z autentycznością i szyfrowaniem oraz optymalizację wydajności za pomocą równoległego przetwarzania.
Aby uzyskać pełny kod źródłowy i dodatkowe przykłady, odwiedź Aspose.Dokumentacja medycznaAby spróbować ognia, Zdobądź darmową licencję tymczasową.
More in this category
- Dlaczego anonimowość DICOM ma znaczenie dla HIPAA i GDPR w przepływach roboczych .NET
- Dostosowane profile prywatności dostosowujące anonimowość DICOM do Polityki Szpitala
- Przygotowanie DICOM Datasets dla AI i Machine Learning z Aspose.Medical
- Przechowywanie metadanych DICOM w bazach danych SQL i NoSQL za pomocą C#
- DICOM Anonimizacja dla Cloud PACS i Teleradiology w C#