Здравствене организације све више требају аутоматске решења за деидентификацију података медицинске слике.У овом водичу ћете научити како да изградите микросервис за анонимност ДИЦОМ-а у АСП.НЕТ Цоре** који прима датотеке ДИСОМА путем ХТТП, анонимизује их користећи конфигурисане профиле и враћа резултате који су неидентификовани.На крају, имаћете архитектуру услуга која је спремна за производњу са изворним кодом узорка.

Табела садржаја

Архитектонски преглед

Мицросервис прати слојну архитектуру са јасном одвајањем забринутости. АПИ слојеви управљају ХТТП захтевима и одговорима кроз АСП.НЕТ Цоре контролере. Сервис слоеви садрже пословну логику користећи Аспасе.Медицински Анонимизатор. Конфигурацијски слојер управљање подешавања профила и апликација опције. Опционални компоненти укључују складиштење за пријављивање и клауинг за обраду бацх.

Ова архитектура омогућава хоризонтално скалирање, лако тестирање и једноставну интеграцију са болничким информационим системима и ПАЦС серверима.

Успостављање пројекта

Počnite stvaranjem novog projekta ASP.NET Core Web API i instaliranjem potrebnog paketa:

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

Изградња АПИ контролера

Креирајте контролер који управља преузимањима датотеке и враћа анонимне ДИКОМ фајлове:

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

Размишљања о безбедности {#безбедносно размишљање}

Приликом увођења ове услуге, имплементирајте ове мере безбедности.

Омогућити ХТТПС да би се осигурало да су све комуникације шифроване у транзиту. Конфигуришите ТЛС 1.2 или већи и преусмеравајте ХТСТП на ХТППС.

Увођење аутентификације користећи ЈВТ токене или АПИ кључеве како би се ограничио приступ овлашћеним клијентима:

[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 да управљају врховима оптерећења без превазилажења услуге.

Закључак {# закључак}

Сада имате комплетан пламен за изградњу микросервиса за анонимност ДИЦОМ-а у АСП.НЕТ Цоре**. Услуга прихвата датотеке ДИСОМА путем ХТТП, примењује конфигурисане профиле анонимизације користећи Аспосе.Медикал, и враћа де-идентификоване податке спремне за истраживање или дељење.

Кључне послове укључују коришћење слојеве архитектуре за одржавање, имплементацију конфигурисаних профила за флексибилност, обезбеђивање услуге аутентификацијом и шифровањем и оптимизацију перформанси уз паралелну обраду.

За комплетни изворни код и додатне примере, посетите Апсос.медицинска документацијада пробају огањ, Добијте бесплатну привремени лиценцу.

More in this category