Le organizzazioni sanitarie hanno sempre più bisogno di soluzioni automatizzate per de-identificare i dati dell’immagine medica.In questa guida imparerai come costruire un microservizio di anonimizzazione di DICOM in ASP.NET Core** che riceve i file DIKOM tramite HTTP, li anonima utilizzando profili configurabili e ritorna i risultati non identificati.Al termine, avrai un’architettura di servizio pronta per la produzione con il codice sorgente di campione.

Tabella dei contenuti

Conoscenza architettonica

Il microservice segue un’architettura stratificata con una chiara separazione delle preoccupazioni. La striscia API gestisce le richieste e le risposte HTTP attraverso i controlli ASP.NET Core. la strisa di servizio contiene la logica aziendale utilizzando l’Aspose.Medical Anonymizer. L’erba di configurazione mantiene le impostazioni del profilo e opzioni di applicazione. I componenti opzionali includono lo storage per il logging e il quoing per la lavorazione del pacchetto.

Questa architettura consente scalazione orizzontale, facile prova e semplice integrazione con i sistemi di informazione ospedalieri e i server PACS.

Impostazione del progetto

Inizia creando un nuovo progetto ASP.NET Core Web API e installando il pacchetto richiesto:

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

Configurare il progetto per grandi file di caricamento in 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();

Implementazione della Layer di Servizio

Crea un’interfaccia e implementazione per il servizio di anonimizzazione:

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

Costruire il controller API

Crea un controller che gestisce le upload di file e restituisce i file DICOM anonimi:

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

Profili configurabili

Permettere che i profili siano configurati tramite appsettings.json:

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

Crea una classe di configurazione e aggiornare il servizio per leggere dalle impostazioni:

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

Consideri di sicurezza

Quando si dispone di questo servizio, applicare queste misure di sicurezza.

Activare HTTPS per garantire che tutte le comunicazioni siano crittografate durante il transito. Configurare TLS 1.2 o superiore e reindirizzare l’HTTP all’https.

Implementazione di autenticazione utilizzando i token JWT o le chiavi API per limitare l’accesso ai clienti autorizzati:

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

** Evitare di memorizzare i file originali** non crittografati sul disco. processi dei file nella memoria quando possibile, e se è necessario lo storage temporaneo, utilizzare i volumi criptati.

Facilita la registrazione di audit per tracciare tutte le operazioni di anonimizzazione, compresi quelli che le hanno richieste e quando:

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

Ottimizzazione delle prestazioni (performance optimization)

Diverse tecniche possono migliorare le prestazioni per scenari ad alta velocità.

Utilizzare l’anonimato in loco quando non è necessario conservare i dati originali nella memoria:

anonymizer.AnonymizeInPlace(dcm);

Activare il trattamento parallelo per le operazioni di 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...
}

Implementazione richiesta di quoing per batte molto grandi utilizzando un messaggino come RabbitMQ o Azure Service Bus per gestire gli spicchi di carico senza sovraccaricare il servizio.

La conclusione (conclusione)

Il servizio accetta i file DICOM tramite HTTP, applica i profili di anonimizzazione configurabili utilizzando Aspose.Medical e restituisce file de-identificati pronti per la ricerca o la condivisione.

Le attività chiave includono l’utilizzo di architettura stratificata per la manutenzione, la realizzazione di profili configurabili per flessibilità, il servizio garantito con autenticazione e crittografia e l’ottimizzazione del rendimento con il trattamento parallelo.

Per il codice sorgente completo e ulteriori esempi, visita il Aspose.documentazione medicaPer provare il fuoco, Ottieni una licenza temporanea gratuita.

More in this category