Como usar Async DICOM JSON Serialization em ASP.NET Core Web APIs

Como usar Async DICOM JSON Serialization em ASP.NET Core Web APIs

Este tutorial demonstra como usar a serialização de async DICOM JSON em APIs web ASP.NET Core. As operações de Asynk são essenciais para aplicações web de alto desempenho para evitar o bloqueio de fio e manter a resposta sob carga.

Por que usar async serialization?

  • a escalabilidade:- Não-bloquear I/O permite o tratamento de pedidos mais concorrentes.

  • • Responsabilidade *:- O servidor web permanece responsivo durante o processamento de arquivos grandes.

    • Eficiência de recursos *:- As ameaças são liberadas enquanto esperam operações I/O.

Título: Preparando o Meio Ambiente

  • Instale o Visual Studio ou qualquer .NET IDE compatível.
  • Criar um novo projeto ASP.NET Core Web API que visa .NET 8.
  • Instale Aspose.Medical do NuGet Package Manager.

Guia passo a passo para a série Async DICOM JSON

Passo 1: Instalar Aspose.Medical

Adicione a Aspose.Medical Library ao seu projeto usando NuGet.

Install-Package Aspose.Medical

Passo 2: Incluir os espaços de nome necessários

Adicione referências aos espaços de nomes necessários no seu controlador.

using Aspose.Medical.Dicom;
using Aspose.Medical.Dicom.Serialization;
using Microsoft.AspNetCore.Mvc;

Passo 3: Crie o Endpoint de Deserificação Async

Crie um ponto final que deserialize o JSON do corpo de solicitação.

[HttpPost("import")]
public async Task<IActionResult> ImportDicomJson()
{
    Dataset? dataset = await DicomJsonSerializer.DeserializeAsync(Request.Body);
    
    if (dataset == null)
        return BadRequest("Invalid DICOM JSON");
    
    return Ok("DICOM data imported successfully");
}

Passo 4: Crie o Endpoint de Serialização Async

Crie um ponto final que serialize DICOM para JSON na resposta.

[HttpGet("export/{filename}")]
public async Task ExportDicomJson(string filename)
{
    DicomFile dcm = DicomFile.Open($"storage/{filename}");
    
    Response.ContentType = "application/json";
    await DicomJsonSerializer.SerializeAsync(Response.Body, dcm.Dataset);
}

Passo 5: Comprar tokens de cancelamento

Passar tokens de cancelamento para o tratamento apropriado da anulação de solicitação.

[HttpPost("process")]
public async Task<IActionResult> ProcessDicomAsync(CancellationToken cancellationToken)
{
    Dataset? dataset = await DicomJsonSerializer.DeserializeAsync(
        Request.Body, 
        cancellationToken
    );
    
    if (cancellationToken.IsCancellationRequested)
        return StatusCode(499, "Client Closed Request");
    
    // Process dataset...
    return Ok();
}

Instalação do ASP.NET Core Controller

Aqui está um controlador completo que implementa async DICOM JSON operações:

using Aspose.Medical.Dicom;
using Aspose.Medical.Dicom.Serialization;
using Microsoft.AspNetCore.Mvc;

namespace DicomApi.Controllers;

[ApiController]
[Route("api/[controller]")]
public class DicomController : ControllerBase
{
    private readonly string _storagePath = "dicom_storage";

    public DicomController()
    {
        Directory.CreateDirectory(_storagePath);
    }

    /// <summary>
    /// Import DICOM JSON and save as DICOM file
    /// </summary>
    [HttpPost("import")]
    public async Task<IActionResult> ImportDicomJson(CancellationToken cancellationToken)
    {
        try
        {
            Dataset? dataset = await DicomJsonSerializer.DeserializeAsync(
                Request.Body, 
                cancellationToken
            );

            if (dataset == null)
                return BadRequest("Failed to deserialize DICOM JSON");

            // Generate unique filename
            string filename = $"{Guid.NewGuid()}.dcm";
            string filepath = Path.Combine(_storagePath, filename);

            // Save as DICOM file
            DicomFile dcm = new DicomFile(dataset);
            dcm.Save(filepath);

            return Ok(new { message = "DICOM imported successfully", filename });
        }
        catch (OperationCanceledException)
        {
            return StatusCode(499, "Request cancelled");
        }
        catch (Exception ex)
        {
            return BadRequest($"Import failed: {ex.Message}");
        }
    }

    /// <summary>
    /// Export DICOM file as JSON stream
    /// </summary>
    [HttpGet("export/{filename}")]
    public async Task ExportDicomJson(string filename, CancellationToken cancellationToken)
    {
        string filepath = Path.Combine(_storagePath, filename);

        if (!System.IO.File.Exists(filepath))
        {
            Response.StatusCode = 404;
            await Response.WriteAsync("File not found");
            return;
        }

        try
        {
            DicomFile dcm = DicomFile.Open(filepath);
            
            Response.ContentType = "application/json";
            Response.Headers["Content-Disposition"] = $"attachment; filename=\"{filename}.json\"";
            
            await DicomJsonSerializer.SerializeAsync(
                Response.Body, 
                dcm.Dataset, 
                writeIndented: true
            );
        }
        catch (OperationCanceledException)
        {
            // Client disconnected
        }
        catch (Exception ex)
        {
            Response.StatusCode = 500;
            await Response.WriteAsync($"Export failed: {ex.Message}");
        }
    }

    /// <summary>
    /// Convert uploaded DICOM file to JSON
    /// </summary>
    [HttpPost("convert")]
    [RequestSizeLimit(100_000_000)] // 100MB limit
    public async Task ConvertDicomToJson(IFormFile file, CancellationToken cancellationToken)
    {
        if (file == null || file.Length == 0)
        {
            Response.StatusCode = 400;
            await Response.WriteAsync("No file uploaded");
            return;
        }

        try
        {
            // Save uploaded file temporarily
            string tempPath = Path.GetTempFileName();
            using (var stream = System.IO.File.Create(tempPath))
            {
                await file.CopyToAsync(stream, cancellationToken);
            }

            // Load and convert
            DicomFile dcm = DicomFile.Open(tempPath);
            
            Response.ContentType = "application/json";
            await DicomJsonSerializer.SerializeAsync(
                Response.Body, 
                dcm.Dataset, 
                writeIndented: true
            );

            // Cleanup temp file
            System.IO.File.Delete(tempPath);
        }
        catch (OperationCanceledException)
        {
            // Client disconnected
        }
        catch (Exception ex)
        {
            Response.StatusCode = 500;
            await Response.WriteAsync($"Conversion failed: {ex.Message}");
        }
    }
}

Configuração de limites de tamanho de solicitação

Para grandes arquivos DICOM, configure limites de solicitação em Program.cs:

var builder = WebApplication.CreateBuilder(args);

// Configure Kestrel for large uploads
builder.WebHost.ConfigureKestrel(options =>
{
    options.Limits.MaxRequestBodySize = 500_000_000; // 500MB
});

// Configure form options
builder.Services.Configure<FormOptions>(options =>
{
    options.MultipartBodyLengthLimit = 500_000_000;
});

var app = builder.Build();

Exemplo de processamento de fluxo

Processar arquivos DICOM sem carregar inteiramente na memória:

[HttpPost("stream-process")]
public async Task StreamProcessDicom(CancellationToken cancellationToken)
{
    // Read JSON from request body stream
    using var reader = new StreamReader(Request.Body);
    string json = await reader.ReadToEndAsync(cancellationToken);
    
    // Deserialize
    Dataset? dataset = DicomJsonSerializer.Deserialize(json);
    
    if (dataset == null)
    {
        Response.StatusCode = 400;
        await Response.WriteAsync("Invalid JSON");
        return;
    }
    
    // Process and stream response
    Response.ContentType = "application/json";
    await DicomJsonSerializer.SerializeAsync(
        Response.Body, 
        dataset, 
        writeIndented: true
    );
}

Melhores práticas de erro

Implementação de erros abrangentes:

[HttpPost("safe-import")]
public async Task<IActionResult> SafeImportDicomJson(CancellationToken cancellationToken)
{
    try
    {
        Dataset? dataset = await DicomJsonSerializer.DeserializeAsync(
            Request.Body, 
            cancellationToken
        );

        if (dataset == null)
            return BadRequest(new { error = "Invalid DICOM JSON format" });

        // Process dataset...
        return Ok(new { success = true });
    }
    catch (OperationCanceledException)
    {
        return StatusCode(499, new { error = "Request cancelled by client" });
    }
    catch (JsonException ex)
    {
        return BadRequest(new { error = "JSON parsing error", details = ex.Message });
    }
    catch (OutOfMemoryException)
    {
        return StatusCode(507, new { error = "File too large to process" });
    }
    catch (Exception ex)
    {
        return StatusCode(500, new { error = "Internal server error", details = ex.Message });
    }
}

Melhores práticas adicionais

Usando Declarações para Streams

Use sempre os padrões de disposição adequados:

using (FileStream fs = System.IO.File.OpenRead(filepath))
{
    // Process stream
}

Configuração Timeout

Configurar horários apropriados para operações longas:

builder.WebHost.ConfigureKestrel(options =>
{
    options.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(2);
    options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(5);
});

Informações adicionais

  • Os métodos Async melhoram a escalabilidade, mas não necessariamente aceleram as solicitações individuais.
  • Use tokens de cancelamento para lidar corretamente com desconectos do cliente.
  • Monitorar o uso da memória ao processar grandes arquivos DICOM.

Conclusão

Este tutorial demonstrou como implementar async DICOM JSON serialization em ASP.NET Core web APIs usando Aspose.Medical. As operações de asínc são essenciais para a construção escalável API de saúde que lidam com grandes dados de imagem médica de forma eficiente.

 Português