Здравните организации все повече се нуждаят от автоматизирани решения за де-идентифициране на медицински изображения данни. В този ръководство ще научите как да изградите DICOM анонимност микросервис в ASP.NET Core, който получава DIKOM файлове чрез HTTP, ги анонимизира, използвайки конфигурируеми профили, и връща де идентифицирани резултати.

Таблица на съдържанието

Преглед на архитектурата

Микросервисът следва слой архитектура с ясно разделяне на притесненията. API-слойката обработва HTTP искания и отговори чрез ASP.NET Core контролери. Сервисовът съдържа бизнес логика с помощта на Aspose.Medical Anonymizer. Конфигурационният слоеве управлява настройките на профила и опциите за приложение. Опционални компоненти включват съхранение за записване и клаузиране за обработка на партиди.

Тази архитектура позволява хоризонтално скалиране, лесно тестване и проста интеграция с болнични информационни системи и PACS сървъри.

Настройване на проекта

Започнете, като създадете нов ASP.NET Core Web API проект и инсталирате необходимия пакет:

dotnet new webapi -n DicomAnonymizationService
cd DicomAnonymizationService
dotnet add package Aspose.Medical

Конфигуриране на проекта за големи файлови изтегляния в 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();

Изпълнение на сервизния слой

Създаване на интерфейс и изпълнение за услугата за анонимност:

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);
    }
}

Изграждане на API контролера

Създайте контролер, който управлява изтеглянето на файлове и връща анонимни 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);
    }
}

Конфигурирани профили

Позволете профилите да бъдат конфигурирани чрез appsettings.json:

{
  "AnonymizationProfiles": {
    "default": "basic",
    "profiles": {
      "basic": ["BasicProfile"],
      "research": ["BasicProfile", "RetainPatientChars"],
      "internal": ["RetainUIDs", "RetainDeviceIdent"],
      "clean": ["CleanGraph", "CleanDesc"],
      "maximum": ["BasicProfile", "CleanGraph", "CleanDesc"]
    }
  }
}

Създайте клас на конфигурация и актуализирайте услугата, за да прочетете от настройките:

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"));

Безопасни съображения за безопасност

При изпълнението на тази услуга се прилагат тези мерки за сигурност.

Осигуряване на HTTPS, за да се гарантира, че всички комуникации са шифровани по време на транзит. Конфигуриране на TLS 1.2 или по-висока и пренасочване на http към http.

Имплементация за автентичност с помощта на JWT токове или API ключове, за да се ограничи достъпа до упълномощени клиенти:

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class AnonymizeController : ControllerBase
{
    // Controller code...
}

Избягвайте съхранението на оригинални файлове**, които не са зашифровани на диска.Процесирайте файлите в паметта, когато е възможно, и ако е необходимо временно съхраняване, използвайте криптирани обеми.

Осигуряване на регистрация на одита за проследяване на всички операции за анонимност, включително кой ги е поискал и когато:

_logger.LogInformation(
    "Anonymization completed - User: {User}, Profile: {Profile}, FileSize: {Size}",
    User.Identity?.Name, profile, file.Length);

Оптимизация на изпълнението

Няколко техники могат да подобрят производителността за високопроизводителни сценарии.

Използвайте анонимност на място, когато не е необходимо да съхранявате оригиналните данни в паметта:

anonymizer.AnonymizeInPlace(dcm);

Осигуряване на паралелна обработка за операциите с партиди:

[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...
}

Имплементация на искане за отваряне за много големи партиди с помощта на съобщение, като RabbitMQ или Azure Service Bus, за да се справят с върховете на натоварването, без да преувеличават услугата.

Заключението е заключение

Сега имате пълен пласт за изграждане на DICOM анонимност микросервис в ASP.NET Core. Услугата приема файловете на DIKOM чрез HTTP, прилага конфигурируеми анонимизация профили с помощта на Aspose.Medical, и връща де-идентифицирани файл готови за проучване или споделяне.

Ключовите задачи включват използването на слоена архитектура за поддръжливост, внедряването на конфигурируеми профили за гъвкавост и осигуряване на услугата с аутентификация и криптиране, както и оптимизирането на производителността с паралелна обработка.

За пълния източен код и допълнителни примери, посетете Апсос.медицинска документацияЗа да изпробваме огъня, Получете безплатна временна лиценза.

More in this category