如何在 ASP.NET 核心 Web APIs 中使用 Async DICOM JSON 序列化
如何在 ASP.NET 核心 Web APIs 中使用 Async DICOM JSON 序列化
本教程展示了如何在 ASP.NET 核心 Web APIs 中使用 Async DICOM JSON 序列化。
為什麼要使用Async Serialization?
可扩展:- 未阻止的 I/O 可处理更频繁的请求。
- 答案*:- 网页服务器在大文件处理过程中保持响应性。
- 资源效率*:- 威胁在等待 I/O 操作时释放。
原标题:准备环境
- 设置 Visual Studio 或任何兼容的 .NET IDE.
- 创建一个新的 ASP.NET Core Web API 项目,针对 .NET 8.
- 在 NuGet Package Manager 中安装 Aspose.Medical。
步骤指南 Async DICOM JSON 序列化
步骤1:安装 Aspose.Medical
使用 NuGet 将 Aspose.Medical 图书馆添加到您的项目中。
Install-Package Aspose.Medical步骤2:包含必要的名称空间
添加您的控制器中的所需名称空间的参考。
using Aspose.Medical.Dicom;
using Aspose.Medical.Dicom.Serialization;
using Microsoft.AspNetCore.Mvc;步骤3:创建Async Deserialization Endpoint
创建一个终点,从请求机构中消除 JSON。
[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");
}步骤4:创建 Async 序列化终点
在回复中创建一个将 DICOM 序列为 JSON 的终点。
[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);
}步骤5:处理取消代币
通过取消标志,以便适当处理请求。
[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();
}完整的 ASP.NET 核心控制器例子
下面是一个完整的控制器实施async DICOM JSON操作:
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}");
}
}
}设置请求尺寸限制
对于大 DICOM 文件,设置请求限制 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();流量处理例子
处理 DICOM 文件,而不完全加载到内存:
[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
);
}错误处理的最佳实践
实施全面的错误处理:
[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 });
}
}更多最佳实践
使用流的声明
始终使用适当的配置模式:
using (FileStream fs = System.IO.File.OpenRead(filepath))
{
// Process stream
}Timeout 配置
设置适合长时间操作的时间:
builder.WebHost.ConfigureKestrel(options =>
{
options.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(2);
options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(5);
});更多信息
- Async 方法提高可扩展性,但不一定加速个人请求。
- 使用取消代币正确处理客户端分离。
- 在处理大 DICOM 文件时监控内存使用。
结论
本教程已经展示了如何在 ASP.NET 核心 Web APIs 中实施 async DICOM JSON 序列化,使用 Aspose.Medical。