Sveikatos priežiūros organizacijoms vis dažniau reikia automatizuotų sprendimų de-identifikuoti medicinos vaizdo duomenis. Šiame vadove sužinosite, kaip sukurti DICOM anonimiškumo mikroserviziją ASP.NET Core, kuri gauna DIKOM failus per HTTP, anonimizuoja juos naudojant konfigūruojamus profilius ir grąžina deidentuotus rezultatus.

Turinio lentelė

Architektūros apžvalga

Microservice sekia sluoksnį architektūrą su aiškiu susirūpinimo atskyrimu. API lapas tvarko HTTP užklausas ir atsakymus per ASP.NET Core valdytojus. Paslaugos laipsnis apima verslo logiką naudojant Aspose.Medical Anonymizer. Konfiguravimo lašas valdo profilio nustatymus ir taikymo parinktis.

Ši architektūra leidžia horizontalią skalavimą, lengvą bandymą ir paprastą integraciją su ligoninės informacinėmis sistemomis ir PACS serveriais.

Įdiegti projektą

Pradėkite kurti naują ASP.NET Core Web API projektą ir įdiegti reikalingą paketą:

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

Konfigūruokite projektą dideliems failų įkrovimams 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();

Paslaugų sluoksnio įgyvendinimas

Sukurkite sąsają ir įgyvendinimą anonimiškumo paslaugai:

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 valdytojo kūrimas

Sukurkite valdytoją, kuris tvarko failų atsisiuntimus ir grąžina anonimiškus DICOM failus:

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

Konfiguruoti profilius

Leiskite profiliams konfigūruoti per appsettings.json:

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

Sukurkite konfigūracijos klasę ir atnaujinkite paslaugą skaityti iš nustatymų:

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

Saugumo apžvalgos {# saugos apžiūros}

Taikydami šią paslaugą, įgyvendinkite šias saugos priemones.

Įveskite HTTPS užtikrinti, kad visos komunikacijos būtų užšifruotos tranzito metu. konfigūruokite TLS 1.2 ar aukštesnį ir persiųskite „HTTP“ į „HTPS“.

Įgyvendinimo autentifikavimas naudojant JWT tokenus arba API raktus, kad būtų ribojamas prieiga į autorizuotus klientus:

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

Nereikia saugoti originalių failų*, kurie nėra šifruoti diske.Kai įmanoma, tvarkykite failus atmintyje ir, jei reikia laikinos saugojimo, naudokite šifrintų tūrių.

Sugebėjimas registruoti auditą, kad būtų galima stebėti visas anonimiškumo operacijas, įskaitant tai, kas juos paprašė, ir kai:

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

Veiksmų optimizavimas

Įvairūs metodai gali pagerinti aukštos kokybės scenarijus.

Naudokite anonimiškumą vietoje, kai nereikia išsaugoti originalių duomenų atmintyje:

anonymizer.AnonymizeInPlace(dcm);

Paralelinė apdorojimo galimybė batch operacijoms:

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

Implementavimo prašymas kreiptis labai dideliems batams naudojant pranešimų kreivę, pvz., RabbitMQ arba Azure Service Bus, kad būtų galima tvarkyti apkrovos spikes be pernelyg didelio aptarnavimo.

Išvada – išvadas

Dabar turite išsamią plokštelę, kad sukurtumėte „DICOM“ anonimiškumo mikroserviziją „ASP.NET Core“**. Paslauga priima „HTTP“ duomenis, taiko konfigūruojamus anoniminio pobūdžio profilius naudojant „Aspose.Medical“ ir grąžina de-identifikuotus failus, kurie yra paruošti tyrimui ar dalijimui.

Pagrindiniai veiksmai apima sluoksnio architektūros naudojimą tvarumui, konfigūruojamų profilių įgyvendinimą lanksčiai, paslaugų užtikrinimą autentiškumu ir šifravimu ir veiklos optimizavimą lygiagrečiu apdorojimu.

Norėdami gauti išsamią šaltinio kodą ir papildomus pavyzdžius, apsilankykite Aspose.Medicininė dokumentacijaIšbandyti ugnį, Gaukite nemokamą laikiną licenciją.

More in this category