Las organizaciones sanitarias necesitan cada vez más soluciones automatizadas para desidentificar los datos de imagen médica.En esta guía, aprenderás cómo construir un microservizo de anonimización de DICOM en ASP.NET Core** que recibe archivos de HTTP, los anonimizará utilizando perfiles configurables y devolverá los resultados de-identificación.Al final, tendrás una arquitectura de servicio preparada para la producción con código de fuente de muestra.

Tabla de contenidos

Conocimiento de la arquitectura

El microservice sigue una arquitectura de capa con una clara separación de preocupaciones. La capa de API maneja las solicitudes y respuestas de HTTP a través de los controladores de ASP.NET Core. la capa del servicio contiene la lógica de negocio utilizando el Aspose.Medical Anonymizer.La capa en configuración gestiona las configuraciones de perfil y las opciones de aplicación. Los componentes opcionales incluyen almacenamiento para registro y cueving para procesamiento de batch.

Esta arquitectura permite la escalación horizontal, la fácil prueba y la integración sencilla con los sistemas de información hospitalaria y los servidores PACS.

Desarrollar el proyecto

Comenzar creando un nuevo proyecto de ASP.NET Core Web API y instalar el paquete requerido:

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

Configure el proyecto para las cargas de archivos grandes en 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();

Implementación de la capa de servicio

Crea una interfaz y implementación para el servicio de anonimización:

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

Construcción del controlador de API

Crea un controlador que gestiona las cargas de archivos y devuelve los ficheros DICOM anónimos:

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

Los perfiles configurables

Permite que los perfiles se configuran a través de appsettings.json:

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

Crea una clase de configuración y actualice el servicio para leer desde las configuraciones:

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

Consideraciones de seguridad

Al implantar este servicio, implementar estas medidas de seguridad.

Activar HTTPS para asegurar que todas las comunicaciones están cifradas en el tránsito. Configure TLS 1.2 o superior y redirigir el TTTP a TTP.

Authenticación de implementación utilizando tokens JWT o claves de API para restringir el acceso a clientes autorizados:

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class AnonymizeController : ControllerBase
{
    // Controller code...
}
  • Evitar el almacenamiento de archivos originales** sin cifrado en el disco. procesar los ficheros en memoria cuando sea posible, y si se requiere almacenaje temporal, utilizar volúmenes cifrados.

Facilitar el registro de auditoría para rastrear todas las operaciones de anonimización, incluido quien las solicitó y cuando:

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

Optimización de las prestaciones

Varias técnicas pueden mejorar el rendimiento para los escenarios de alta velocidad.

Use anonimización en lugar cuando no necesitas guardar los datos originales en la memoria:

anonymizer.AnonymizeInPlace(dcm);

Activa el procesamiento paralelo para las operaciones de batch:

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

Implementación de la solicitud de queu para batallas muy grandes utilizando una queue de mensajes como RabbitMQ o Azure Service Bus para manejar los picos de carga sin sobrecargar el servicio.

La conclusión

Ahora tienes un plan completo para construir un microservizo de anonimización de DICOM en ASP.NET Core**. El servicio acepta los archivos de HTTP, aplica los perfiles de anonymización configurables utilizando Aspose.Medical, y devuelve los ficheros de-identificados listos para la investigación o compartir.

Las tareas clave incluyen el uso de arquitectura de capa para la mantenimiento, la implementación de perfiles configurables para flexibilidad, asegurar el servicio con autenticación y cifrado, y optimizar el rendimiento con el procesamiento paralelo.

Para el código fuente completo y ejemplos adicionales, visite el Aspose.Documentación médicaPara probar el fuego, Obtenga una licencia temporal gratuita.

More in this category