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

使用Razor、JavaScript/C#实现页面文件上传:点击创建按钮文件未保存且报错

Razor页面文件上传问题排查与解决

针对你遇到的文件未保存且弹出“无法访问此站点”的问题,结合你提供的代码,从后端、前端两方面梳理问题和修复方案:

一、后端代码问题修复

你提供的代码不完整,且存在几个关键问题:

1. 补充完整请求逻辑

当前代码仅处理了文件保存,缺少将Contratos实体保存到数据库的逻辑,也没有请求响应返回。如果没有正确的返回结果,前端会因请求超时或无响应报错。补充完整代码:

private readonly YourDbContext _context;
private readonly IWebHostEnvironment _webHostEnv;

// 构造函数注入DbContext和IWebHostEnvironment
public ContratosController(YourDbContext context, IWebHostEnvironment webHostEnv)
{
    _context = context;
    _webHostEnv = webHostEnv;
}

[HttpPost]
public async Task<IActionResult> Create([Bind("ID,Inicio,Vencimento,ImovelId,LocatarioId,Ativo,ContratoPdf")] Contratos contratos, IFormFile arquivo)
{
    if (ModelState.IsValid)
    {
        try
        {
            if (arquivo != null && arquivo.Length > 0)
            {
                // 替换硬编码路径,使用IWebHostEnvironment获取安全目录(推荐存到wwwroot下的子目录)
                string diretorioDestino = Path.Combine(_webHostEnv.WebRootPath, "Arquivos", "Contratos");
                if (!Directory.Exists(diretorioDestino))
                {
                    Directory.CreateDirectory(diretorioDestino);
                }
                // 生成唯一文件名,避免重名覆盖
                string nomeArquivo = $"{Guid.NewGuid()}_{Path.GetFileName(arquivo.FileName)}";
                string caminhoCompleto = Path.Combine(diretorioDestino, nomeArquivo);

                using (var stream = new FileStream(caminhoCompleto, FileMode.Create))
                {
                    await arquivo.CopyToAsync(stream);
                }
                contratos.ContratoPdf = nomeArquivo;
            }

            // 将实体保存到数据库
            _context.Add(contratos);
            await _context.SaveChangesAsync();
            // 重定向到列表页,返回正确响应
            return RedirectToAction(nameof(Index));
        }
        catch (Exception ex)
        {
            // 捕获异常,添加到ModelState,返回页面显示错误
            ModelState.AddModelError(string.Empty, $"文件保存失败:{ex.Message}");
        }
    }
    // 模型验证失败或出错时,返回创建页面
    return View(contratos);
}

2. 关键优化点

  • 避免硬编码路径:用IWebHostEnvironment获取WebRootPath(wwwroot目录),避免部署时权限或路径不存在问题,同时保证跨平台兼容性。
  • 生成唯一文件名:用Guid拼接原文件名,防止同名文件覆盖。
  • 添加异常捕获:捕获文件保存或数据库操作的异常,将错误信息返回前端,避免请求直接崩溃导致“无法访问站点”。
  • 完善请求响应:无论成功失败都返回明确的ActionResult,确保前端能正确接收响应。

二、前端Razor页面配置

前端表单必须满足以下要求,否则文件无法正确提交:

1. 表单设置enctype属性

表单必须添加enctype="multipart/form-data",否则文件不会被包含在请求中:

<form asp-action="Create" enctype="multipart/form-data">
    <!-- 其他表单字段 -->
    <div class="form-group">
        <label asp-for="ContratoPdf" class="control-label"></label>
        <input type="file" name="arquivo" class="form-control" />
        <span asp-validation-for="ContratoPdf" class="text-danger"></span>
    </div>
    <div class="form-group">
        <input type="submit" value="创建" class="btn btn-primary" />
    </div>
</form>

2. 文件输入名称匹配

文件输入的name属性必须和后端方法的IFormFile参数名一致(这里是arquivo),否则模型绑定失败,arquivo会为null。

三、常见额外问题排查

如果以上修复后仍报错,检查以下点:

  • 目录权限:确保应用程序对目标目录有读写权限(比如IIS应用池身份、开发时的当前用户)。
  • 文件大小限制:ASP.NET Core默认限制上传文件大小为30MB,若上传大文件,需在Program.cs中配置:
builder.Services.Configure<FormOptions>(options =>
{
    options.MultipartBodyLengthLimit = 104857600; // 100MB
});
  • AJAX上传的特殊处理:如果用JavaScript AJAX提交,必须用FormData对象,且不能设置contentType为application/json:
document.querySelector('form').addEventListener('submit', async function(e) {
    e.preventDefault();
    const formData = new FormData(this);
    const response = await fetch(this.action, {
        method: 'POST',
        body: formData
    });
    if (response.ok) {
        window.location.href = '/Contratos/Index';
    } else {
        // 处理错误
        const errorText = await response.text();
        alert(errorText);
    }
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 10:31:29