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

ASP.NET Core 5 中如何向指定用户发送通过表单生成的文件

ASP.NET Core 5 MVC 导师向学生发送专属教学大纲图片全流程解决方案

1. 数据库设计方案

  • 不需要重构原有用户表,仅扩展关联表即可,禁止直接将图片二进制存入数据库,仅存储文件元数据,实体文件单独存储在服务器独立目录
  • 新增专属大纲分发表,核心字段如下:
    • Id 主键自增
    • SenderId 导师用户ID,关联用户表主键
    • ReceiverId 学生用户ID,关联用户表主键
    • SaveFileName 服务器存储的唯一文件名,用Guid生成避免重名
    • OriginalFileName 展示用的原始文件名,比如「张三-2024级计算机专业教学大纲.png」
    • FileSize 文件大小,单位为字节
    • ContentType 文件MIME类型,存image/png/image/jpeg这类标识
    • SendTime 发送时间
    • IsRead 可选字段,标记学生是否已查看该大纲
  • 实体文件存储路径建议放在项目wwwroot目录之外,避免未授权用户直接通过静态文件地址访问

2. 导师端上传/生成文件功能实现

  • 若为导师手动上传大纲,提交表单的ViewModel新增IFormFile类型字段接收图片文件;若为表单自动生成图片,用SixLabors.ImageSharp开源库动态绘制内容生成图片流即可,跨平台兼容性优于系统自带的System.Drawing
  • 上传核心代码示例:
[HttpPost]
[Authorize(Roles = "导师")]
public async Task<IActionResult> SendOutline(SendOutlineViewModel model)
{
    if (!ModelState.IsValid) return View(model);
    // 校验目标学生是否存在
    var student = await _context.Users.FirstOrDefaultAsync(u => u.Id == model.StudentId && u.UserType == 0);
    if (student == null)
    {
        ModelState.AddModelError("", "指定学生不存在");
        return View(model);
    }
    // 校验文件格式、大小
    var allowedExt = new[] { ".png", ".jpg", ".jpeg" };
    var ext = Path.GetExtension(model.OutlineFile.FileName).ToLower();
    if (!allowedExt.Contains(ext) || model.OutlineFile.Length > 2 * 1024 * 1024)
    {
        ModelState.AddModelError("", "仅支持2M以内的png/jpg格式图片");
        return View(model);
    }
    // 生成唯一存储文件名
    var saveName = $"{Guid.NewGuid()}{ext}";
    var savePath = Path.Combine(_webHostEnvironment.ContentRootPath, "OutlineFiles", saveName);
    // 写入文件到磁盘
    await using var stream = new FileStream(savePath, FileMode.Create);
    await model.OutlineFile.CopyToAsync(stream);
    // 写入数据库记录
    var fileRecord = new OutlineFileRecord
    {
        SenderId = User.FindFirstValue(ClaimTypes.NameIdentifier),
        ReceiverId = model.StudentId,
        SaveFileName = saveName,
        OriginalFileName = $"{student.Name}-教学大纲{ext}",
        FileSize = model.OutlineFile.Length,
        ContentType = model.OutlineFile.ContentType,
        SendTime = DateTime.Now
    };
    _context.OutlineFileRecords.Add(fileRecord);
    await _context.SaveChangesAsync();
    return RedirectToAction("SendHistory");
}

3. 学生端下载/预览功能实现

  • 所有文件访问必须走权限校验接口,禁止直接暴露磁盘存储路径
  • 访问文件核心代码示例:
[Authorize]
public async Task<IActionResult> GetOutline(int fileId, bool isDownload = false)
{
    var currentUserId = User.FindFirstValue(ClaimTypes.NameIdentifier);
    // 校验文件归属权限
    var fileRecord = await _context.OutlineFileRecords
        .FirstOrDefaultAsync(f => f.Id == fileId && f.ReceiverId == currentUserId);
    if (fileRecord == null) return Forbid();
    var filePath = Path.Combine(_webHostEnvironment.ContentRootPath, "OutlineFiles", fileRecord.SaveFileName);
    if (!System.IO.File.Exists(filePath)) return NotFound("文件已被删除");
    var fileStream = System.IO.File.OpenRead(filePath);
    // 预览直接返回文件流,下载指定文件名即可
    return isDownload ? File(fileStream, fileRecord.ContentType, fileRecord.OriginalFileName) : File(fileStream, fileRecord.ContentType);
}
  • 前端展示图片直接调用预览接口即可:<img src="/Outline/GetOutline?fileId=@item.Id" alt="教学大纲">
  • 下载按钮调用带下载参数的接口即可:<a href="/Outline/GetOutline?fileId=@item.Id&isDownload=true" target="_blank">下载大纲</a>

4. 额外优化建议

  • 可新增发送成功后给学生推送站内信的逻辑,避免学生错过通知
  • 定期清理已过期的大纲文件,降低服务器存储占用
  • 若用户量较大,可将文件存储替换为云对象存储,逻辑仅需修改文件读写部分即可,数据库结构不需要调整

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 21:45:06