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

Blazor Server中MultipartFormDataContent在Razor页面失效但Swagger可用

Blazor Server文件上传API接收不到文件问题解决

问题描述

在.NET 7.0的Blazor Server项目中,参考微软官方文档实现文件上传功能,API在Swagger中可正常接收文件并完成上传,但通过Razor页面调用时,API控制器中的files.Count始终为0,无法获取传输的文件。

相关代码

Razor页面代码

@page "/file-upload-2"
@using System.Linq
@using System.Net.Http.Headers
@using Dostware.PromoPazarV1.Files
@using Dostware.PromoPazarV1.Models
@using Dostware.PromoPazarV1.Models.UploadResult
@using Microsoft.Extensions.Logging
@using System.Net.Http.Json
@inject HttpClient Http
@inject ILogger<ImageUpload> Logger
@inject FileUploadAppService FileUploadAppService

<PageTitle>File Upload 2</PageTitle>

<h1>File Upload Example 2</h1>

<p>
    <label>
        Upload up to @maxAllowedFiles files:
        <InputFile OnChange="OnInputFileChange" multiple />
    </label>
</p>

@if (files.Count > 0)
{
    <div class="card">
        <div class="card-body">
            <ul>
                @foreach (var file in files)
                {
                    <li>
                        File: @file.Name
                        <br>
                        @if (FileUpload(uploadResults, file.Name, Logger,
                       out var result))
                        {
                            <span>
                                Stored File Name: @result.StoredFileName
                            </span>
                        }
                        else
                        {
                            <span>
                                There was an error uploading the file
                                (Error: @result.ErrorCode).
                            </span>
                        }
                    </li>
                }
            </ul>
        </div>
    </div>
}

@code {
    private List<File> files = new();
    private List<UploadResult> uploadResults = new();
    private int maxAllowedFiles = 3;
    private bool shouldRender;

    protected override bool ShouldRender() => shouldRender;

    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        shouldRender = false;
        long maxFileSize = 1024 * 100000;
        var upload = false;

        using var content = new MultipartFormDataContent();

        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            if (uploadResults.SingleOrDefault(
                f => f.FileName == file.Name) is null)
            {
                try
                {
                    files.Add(new() { Name = file.Name });

                    var fileContent =
                        new StreamContent(file.OpenReadStream(maxFileSize));

                    fileContent.Headers.ContentType =
                        new MediaTypeHeaderValue(file.ContentType);

                    content.Add(
                        content: fileContent,
                        name: "\"files\"",
                        fileName: file.Name);

                    upload = true;
                }
                catch (Exception ex)
                {
                    Logger.LogInformation(
                        "{FileName} not uploaded (Err: 6): {Message}",
                        file.Name, ex.Message);

                    uploadResults.Add(
                        new()
                            {   
                                FileName = file.Name,
                                ErrorCode = 6,
                                Uploaded = false
                            });
                }
            }
        }

        if (upload)
        {
            var response = await FileUploadAppService.PostFile(content);
        }

        shouldRender = true;
    }

    private static bool FileUpload(IList<UploadResult> uploadResults,
        string? fileName, ILogger<ImageUpload> logger, out UploadResult result)
    {
        result = uploadResults.SingleOrDefault(f => f.FileName == fileName) ?? new();

        if (!result.Uploaded)
        {
            logger.LogInformation("{FileName} not uploaded (Err: 5)", fileName);
            result.ErrorCode = 5;
        }

        return result.Uploaded;
    }

    private class File
    {
        public string? Name { get; set; }
    }
}

API控制器代码

[HttpPost("PostFile")]
public async Task<ActionResult<IList<UploadResult>>> PostFile(
    [FromForm] IEnumerable<IFormFile> files)
{
    var maxAllowedFiles = 3;
    long maxFileSize = 1024 * 500000;
    var filesProcessed = 0;
    var resourcePath = new Uri($"{Request.Scheme}://{Request.Host}/");
    List<UploadResult> uploadResults = new();

    foreach (var file in files)
    {
        var uploadResult = new UploadResult();
        string trustedFileNameForFileStorage;
        var untrustedFileName = file.FileName;
        uploadResult.FileName = untrustedFileName;
        var trustedFileNameForDisplay =
            WebUtility.HtmlEncode(untrustedFileName);   

        if (filesProcessed < maxAllowedFiles)
        {
            if (file.Length == 0)
            {
                logger.LogInformation("{FileName} length is 0 (Err: 1)",
                    trustedFileNameForDisplay);
                uploadResult.ErrorCode = 1;
            }
            else if (file.Length > maxFileSize)
            {
                logger.LogInformation("{FileName} of {Length} bytes is " +
                    "larger than the limit of {Limit} bytes (Err: 2)",
                    trustedFileNameForDisplay, file.Length, maxFileSize);
                uploadResult.ErrorCode = 2;
            }
            else
            {
                try
                {
                    trustedFileNameForFileStorage = Path.GetRandomFileName();
                    var originalFileName = file.FileName;
                    var fileExtension = Path.GetExtension(originalFileName);
                    var newFileName = trustedFileNameForFileStorage + fileExtension;
                    var path = Path.Combine(env.ContentRootPath, "wwwroot", "uploads", newFileName);

                    await using FileStream fs = new(path, FileMode.Create);
                    await file.CopyToAsync(fs);

                    logger.LogInformation("{FileName} saved at {Path}", 
                        trustedFileNameForDisplay, path);
                    uploadResult.Uploaded = true;
                    uploadResult.StoredFileName = trustedFileNameForFileStorage;
                }
                catch (IOException ex)
                {
                    logger.LogError("{FileName} error on upload (Err: 3): {Message}",
                        trustedFileNameForDisplay, ex.Message);
                    uploadResult.ErrorCode = 3;
                }
            }

            filesProcessed++;
        }
        else
        {
            logger.LogInformation("{FileName} not uploaded because the " +
                "request exceeded the allowed {Count} of files (Err: 4)",
                trustedFileNameForDisplay, maxAllowedFiles);
            uploadResult.ErrorCode = 4;
        }

        uploadResults.Add(uploadResult);
    }

    return new CreatedResult(resourcePath, uploadResults);
}

服务层代码

public async Task<ActionResult<IList<UploadResult>>> PostFile(MultipartFormDataContent multipartFormDataContent)
{
    try
    {
        try
        {
            var response =  _http.PostAsync("FileSave/PostFile", multipartFormDataContent);
        }
        catch (Exception ex)
        {
            var den = ex.Message;
        }
    }   
    catch (Exception ex)
    {
        var den = ex.Message;
    }

    return new CreatedResult("", uploadResults);
}

解决方案

  • 修正MultipartFormDataContent参数名格式:Razor页面中content.Add方法的name参数带多余双引号,导致控制器无法识别。将name: "\"files\""改为name: "files"。
  • 等待异步请求完成:服务层的PostAsync未用await会导致请求未完成就返回,修正为var response = await _http.PostAsync("FileSave/PostFile", multipartFormDataContent);,并添加响应处理逻辑(比如读取返回的上传结果)。
  • 配置HttpClient BaseAddress:确保服务层的_http实例配置了正确的API基础地址,可在Program.cs中通过AddHttpClient注入时指定。
  • 可选:手动设置边界符:若上述修改无效,可手动指定MultipartFormDataContent的边界符,避免自动生成的边界符解析异常:var boundary = $"----{Guid.NewGuid():N}"; using var content = new MultipartFormDataContent(boundary);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 04:37:36