Hälso- och sjukvårdsorganisationer behöver alltmer automatiserade lösningar för att de-identifiera medicinska bilddata. I den här guiden lär du dig hur man bygger en DICOM anonymisering mikroservice i ASP.NET Core som mottar DICom-filer via HTTP, anonymiserar dem med hjälp av konfigurerbara profiler och returnerar de identifierade resultaten.

Tabell av innehåll

Översikt över arkitektur

Microservice följer en lagrad arkitektur med tydlig separation av bekymmer. API-lagret hanterar HTTP-förfrågningar och svar via ASP.NET Core-kontroller. Tjänstelaget innehåller affärslogiken med hjälp av Aspose.Medical Anonymizer. Konfigurationslagret förvaltar profilinställningarna och applikationsalternativ. Optionella komponenter inkluderar lagring för loggning och quuing för batch bearbetning.

Denna arkitektur möjliggör horisontell skalning, enkel testning och enkel integration med sjukhusinformationssystem och PACS-servrar.

Ställ upp projektet

Börja med att skapa ett nytt ASP.NET Core Web API-projekt och installera det nödvändiga paketet:

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

Konfigurera projektet för stora filhämtningar i 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();

Implementering av Service Layer

Skapa ett gränssnitt och implementering för anonymiseringstjänsten:

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

Bygg API-kontrollen

Skapa en drivrutin som hanterar filhämtningar och returnerar anonymiserade DICOM-filer:

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

Konfigurerade profiler

Tillåta profiler att konfigureras via appsettings.json:

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

Skapa en konfigurationsklass och uppdatera tjänsten för att läsa från inställningar:

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

Säkerhetsfrågor

Vid implementering av denna tjänst, genomföra dessa säkerhetsåtgärder.

Aktivera HTTPS för att säkerställa att alla kommunikationer är krypterade i transit. Konfigurera TLS 1.2 eller högre och omdirigera http till http.

Implementation autentisering med hjälp av JWT-tokener eller API-nycklar för att begränsa åtkomst till auktoriserade kunder:

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

** Undvik att lagra ursprungliga filer** som inte är krypterade på en skiva. bearbetar filerna i minnet när det är möjligt, och om tillfällig lagring behövs, använd kryptade volymer.

Att möjliggöra revisionslogging för att spåra alla anonymiseringsverksamheter inklusive vem som begärt dem och när:

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

Förmånsoptimering = Performance Optimization

Flera tekniker kan förbättra prestanda för högpresterande scenarier.

Anonymisering på plats när du inte behöver behålla originaldata i minnet:

anonymizer.AnonymizeInPlace(dcm);

** Tillåter parallell bearbetning** för batchoperationer:

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

Implementera en begäran om att skräddarsy för mycket stora partier med hjälp av en meddelandeskruv som RabbitMQ eller Azure Service Bus för att hantera laddningspikes utan att överbelasta tjänsten.

Slutsatser från #conclusion

Du har nu ett komplett formulär för att bygga en DICOM anonymisering microservice i ASP.NET Core. Tjänsten accepterar DICom-filer via HTTP, tillämpar konfigurerbara anonymiseringsprofiler med Aspose.Medical och returnerar de-identifierade filer redo för forskning eller delning.

Viktiga åtgärder inkluderar användning av lagrad arkitektur för underhåll, implementering av konfigurbara profiler för flexibilitet, säkerställande av tjänsten med autentisering och kryptering och optimering av prestanda med parallell bearbetning.

För den fullständiga källkoden och ytterligare exempel, besök Aspose.Medicinsk dokumentationFör att prova elden, Få en gratis tillfällig licens.

More in this category