You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core Web API结合Blazor WASM的食谱文件上传方案咨询

生产环境食谱上传功能的最优实现方案

针对你的场景,不推荐使用Base64格式在JSON中传输图片,更适合采用MultipartFormDataContent结合ASP.NET Core自动模型绑定的方式,既解决复杂模型的传输问题,又保证生产环境的性能和可维护性。

为什么不选Base64?

  • 体积膨胀:Base64会让图片文件体积增大30%左右,占用更多带宽,传输耗时更长,大图片场景下问题更明显。
  • 性能开销:JSON序列化/反序列化大体积Base64字符串会消耗更多CPU和内存,后端还要额外解码成文件,增加服务器负载。
  • 限制较多:部分HTTP服务器或代理对大JSON请求有大小限制,容易触发请求截断或报错。

推荐实现步骤

1. 调整后端Dto与API接口

首先拆分原有的RecipeDto,将文件和结构化数据分离,避免模型混杂:

// 用于接收食谱结构化数据的Dto
public class CreateRecipeDto
{
    [Required]
    [MaxLength(100)]
    public string Name { get; set; }
    
    [Required]
    public string Description { get; set; }
    
    public string? PrepDescription { get; set; }
    
    [Required]
    public string Category { get; set; }
    
    public bool LunchBox { get; set; }
    
    [Required]
    public string Diet_Category { get; set; }
    
    [Required]
    public string AuthorName { get; set; }
    
    [Required]
    public List<IngredientDto> Ingredients { get; set; } = new();
}

public class IngredientDto
{
    public int Id { get; set; }
    
    [Required]
    public string Name { get; set; }
    
    public bool Countable { get; set; }
    
    public int? Quantity { get; set; }
}

然后修改API接口,通过[FromForm]自动绑定结构化数据,单独接收文件:

[HttpPost("upload")]
public async Task<ActionResult> UploadRecipe([FromForm] CreateRecipeDto recipe, IFormFile recipeImg)
{
    var maxFileSize = 1024 * 500; // 限制500KB
    var allowedContentTypes = new[] { "image/jpeg", "image/png", "image/webp" };
    var imageStoragePath = _config.GetValue<string>("Paths:RecipeImgPath");

    // 基础校验
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    
    if (recipeImg == null || recipeImg.Length == 0)
    {
        return BadRequest("请选择要上传的食谱图片");
    }
    
    if (recipeImg.Length > maxFileSize)
    {
        return BadRequest($"图片大小不能超过{maxFileSize / 1024}KB");
    }
    
    if (!allowedContentTypes.Contains(recipeImg.ContentType))
    {
        return BadRequest("仅支持JPG、PNG、WebP格式的图片");
    }

    try
    {
        // 生成安全的文件名,避免路径遍历攻击
        var fileExtension = Path.GetExtension(recipeImg.FileName).ToLowerInvariant();
        var trustedFileName = $"{Guid.NewGuid()}{fileExtension}";
        var savePath = Path.Combine(imageStoragePath, trustedFileName);

        // 保存文件
        await using var fs = new FileStream(savePath, FileMode.Create);
        await recipeImg.CopyToAsync(fs);

        // 这里将食谱数据和图片路径存入数据库
        // 例如:_dbContext.Recipes.Add(new Recipe { ..., ImgPath = trustedFileName });
        // await _dbContext.SaveChangesAsync();

        return Ok("食谱上传成功");
    }
    catch (Exception ex)
    {
        // 记录异常日志(建议用ILogger)
        // _logger.LogError(ex, "上传食谱图片失败");
        return StatusCode(500, "上传失败,请稍后重试");
    }
}

2. Blazor WASM前端实现

前端将结构化数据序列化为JSON字符串,与图片一起加入MultipartFormDataContent,无需手动逐个绑定属性:

@inject HttpClient HttpClient
@* 假设你有一个表单绑定CreateRecipeDto模型 *@

<button @onclick="HandleSubmit">提交食谱</button>
<InputFile OnChange="OnFileSelected" />

@code {
    private CreateRecipeDto _recipe = new();
    private IBrowserFile _selectedFile;

    private void OnFileSelected(InputFileChangeEventArgs e)
    {
        _selectedFile = e.File;
    }

    private async Task HandleSubmit()
    {
        if (_selectedFile == null)
        {
            // 提示用户选择图片
            return;
        }

        using var content = new MultipartFormDataContent();

        // 将食谱数据序列化为JSON,添加到FormData
        var recipeJson = JsonSerializer.Serialize(_recipe);
        content.Add(new StringContent(recipeJson, Encoding.UTF8, "application/json"), "recipe");

        // 添加图片文件
        var fileContent = new StreamContent(_selectedFile.OpenReadStream(maxAllowedSize: 1024 * 500));
        fileContent.Headers.ContentType = new MediaTypeHeaderValue(_selectedFile.ContentType);
        content.Add(fileContent, "recipeImg", _selectedFile.Name);

        var response = await HttpClient.PostAsync("api/recipes/upload", content);

        if (response.IsSuccessStatusCode)
        {
            // 处理成功逻辑,如跳转列表页、提示成功
        }
        else
        {
            var errorMsg = await response.Content.ReadAsStringAsync();
            // 提示错误信息
        }
    }
}

生产环境额外优化建议

  • 文件存储:避免直接存在服务器本地,推荐使用对象存储服务,方便扩容、备份和CDN加速。
  • 异步处理:如果需要对图片进行压缩、格式转换等操作,可将这些任务放入后台队列,避免阻塞API请求。
  • 权限控制:添加身份验证(如JWT),确保只有授权用户能上传食谱。
  • 日志监控:详细记录上传请求的状态、异常信息,方便排查问题。

内容的提问来源于stack exchange,提问作者Sztajnke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 06:16:01