文件存储与上传
本模块旨在让文件上传变得极度简单。无需复杂的流处理,无需关心物理路径,只需要处理一个字符串路径。
1. 极速上手 (Quick Start)
三步即可完成文件上传功能:放控件 -> 绑模型 -> 存数据库。
第一步:View (放控件)
在你的 .cshtml 页面中,使用 vc:file-upload 组件。
<form asp-action="UpdateProfile" method="post">
<!-- 1. 绑定你的 ViewModel 属性 -->
<!-- 2. 指定上传到的"桶" (upload-endpoint) -->
<vc:file-upload
asp-for="IconPath"
upload-endpoint="/upload/avatar"
allowed-extensions="jpg png">
</vc:file-upload>
<button type="submit">提交</button>
</form>
第二步:ViewModel (绑模型)
在 ViewModel 中,只需要定义一个 string 类型的属性来接收上传后的路径。
public class UpdateProfileViewModel
{
// 这里存的只是路径字符串,例如 "avatar/2025/01/01/xxx.jpg"
[Required] // 必填校验
public string IconPath { get; set; }
}
第三步:Controller (存数据库)
在 Controller 中,像处理普通文本一样处理这个路径。
[HttpPost]
public async Task<IActionResult> UpdateProfile(UpdateProfileViewModel model)
{
if (!ModelState.IsValid) return View(model);
var user = await _userManager.GetUserAsync(User);
// 直接把路径字符串存入数据库即可
user.IconPath = model.IconPath;
await _userManager.UpdateAsync(user);
return RedirectToAction(nameof(Index));
}
完成! 你已经实现了文件上传、自动存储、和业务关联。
2. 进阶:约束与校验
为了保证安全和数据的规范性,建议加上以下约束。
2.1 锁定上传目录 (Bucket Isolation)
防止用户把发票上传到头像的目录里。
在 ViewModel 中使用正则限制路径的前缀:
public class UpdateProfileViewModel
{
[Required]
[Display(Name = "User Icon")]
// 强制要求路径必须以 Workspace/avatar 开头
[RegularExpression(@"^Workspace/avatar.*", ErrorMessage = "请上传正确的头像文件。")]
public string IconPath { get; set; }
}
2.2 扩展名与大小限制
- 前端限制:在 View 组件上设置。
<vc:file-upload ... allowed-extensions="jpg png pdf" max-size-in-mb="10" /> - 后端限制:在 ViewModel 或 Controller 中进一步校验(组件已内置基础校验)。
3. 文件展示
图片存进去了,怎么显示出来?使用 StorageService。
@inject Aiursoft.Template.Services.FileStorage.StorageService Storage
<!-- 自动转换为可访问的 HTTP URL -->
<img src="@Storage.RelativePathToInternetUrl(Model.IconPath)" />
隐私与裁剪
支持在 URL 后加参数进行实时处理: * ?w=200: 缩放到 200px 宽。 * ?square=true: 自动裁剪正方形。 * 隐私保护:所有通过此方式访问的图片,都会自动清除 EXIF 信息 (GPS、相机参数等),保护用户隐私。
4. 核心原理 (Understanding)
为什么这么简单?因为采用了 "两步走 (Two-Step)" 策略:
- 上传 (Upload): 此过程与业务无关。用户选文件 -> 传到临时的文件服务器 -> 拿到一个路径字符串 (e.g.
Workspace/avatar/2025/...)。 - 提交 (Submit): 用户点击保存按钮,只是把这个字符串也就是路径,作为一个普通字段提交给了你的业务 Controller。
高级设计细节
上面的内容已经可以支撑你构建一个完善的文件存储了。但是,一个文件存储为了安全、可靠、可组织、避免黑客耗尽磁盘空间,我们仍然需要讨论大量细节。
如果你需要高级开发技巧,请阅读完整的 文件存储设计细节。