在 Razor 页面上使用选择列表和文件上传
Posted
技术标签:
【中文标题】在 Razor 页面上使用选择列表和文件上传【英文标题】:Using a Select List Alongside a File Upload on Razor Pages 【发布时间】:2020-12-11 02:04:06 【问题描述】:背景: 该程序使用 .Net Core 3.1 和 EF Core,使用代码优先的方法利用本地 MSSQL 实例。 问题的相关实体包括代理
public class Agent
public int AgentID get; set;
public string Name get; set;
public string Number get; set;
public ICollection<SysInfo> SysInfo get; set;
与SysInfo是一对多的关系
public class SysInfo
public int SysInfoID get; set;
public int AgentID get; set;
public byte[] Content get; set;
public Agent Agent get; set;
DB 是使用 EF Core 迁移构建的,CRUD 页面是为代理实体搭建的。 SysInfo 旨在存储系统信息文件。 我从在https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-3.1#file-upload-scenarios 找到的示例开始,并修改了 UploadDbModel 以包含一个选择列表。
public class BufferedSingleFileUploadDbModel:PageModel
[BindProperty]
public BufferedSingleFileUploadDb FileUpload get; set;
public SelectList AgentNameSL get; set;
public void PopulateAgentsDropDownList(WindowsAuthTest3Context _context, object selectedAgent = null)
var agentsQuery = from a in _context.Agent
orderby a.Name
select a;
AgentNameSL = new SelectList(agentsQuery.AsNoTracking(), "AgentID", "Name", selectedAgent);
public class BufferedSingleFileUploadDb
[Required]
[Display(Name ="File")]
public IFormFile FormFile get; set;
上传页面是从标准 EF 核心 Create 模板中搭建出来的,并被修改为继承上面的类、填充选择列表、处理上传并创建记录。
问题: 当我尝试将选择列表与多部分 enctype 网格化时,我做错了。加载页面时选择列表拒绝填充。
CS 文件:
public class UploadModel : BufferedSingleFileUploadDbModel
private readonly WindowsAuthTest3.Data.WindowsAuthTest3Context _context;
public UploadModel(WindowsAuthTest3.Data.WindowsAuthTest3Context context)
_context = context;
public IActionResult OnGet()
PopulateAgentsDropDownList(_context);
return Page();
[BindProperty]
public SysInfo SysInfo get; set;
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see https://aka.ms/RazorPagesCRUD.
public async Task<IActionResult> OnPostUploadAsync()
using(var memoryStream = new MemoryStream())
await FileUpload.FormFile.CopyToAsync(memoryStream);
SysInfo.Content = memoryStream.ToArray();
if (!ModelState.IsValid)
return Page();
_context.SysInfo.Add(SysInfo);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
CShtml 文件:
@page
@model WindowsAuthTest3.Pages.Infos.UploadModel
@
ViewData["Title"] = "Upload";
<h1>Upload</h1>
<h4>SysInfo</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form enctype="multipart/form-data" method="post">
<div class="form-group">
<label asp-for="SysInfo.AgentID" class="control-label"></label>
<select asp-for="SysInfo.AgentID" class="form-control" asp-items="@Model.AgentNameSL"></select>
</div>
<div class="form-group">
<label asp-for="FileUpload.FormFile"></label>
<input asp-for="FileUpload.FormFile" type="file">
</div>
<div class="form-group">
<input asp-page-handler="Upload" class="btn btn-primary" type="submit" value="Upload">
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
@section Scripts
@await Html.RenderPartialAsync("_ValidationScriptsPartial");
问题:
-
选择列表可以包含在多部分 enctypes 中吗?如果可以,我是不是写错了?
如果没有,我将如何构建多个 post 方法来完成在上传文件时设置外键?我考虑过让代理 ID 为空,然后通过编辑页面分配它,但这感觉像是一个很糟糕的解决方法,容易出现用户错误。
【问题讨论】:
【参考方案1】:分离发布方法后,我注意到选择列表会填充,然后在上传文件后消失。这似乎是由于 asp-page-handler 造成的。我将代码组合到常规 post 方法中,如下所示,现在一切正常。
CSHTML
<div class="row">
<div class="col-md-4">
<form enctype="multipart/form-data" method="post">
<div class="form-group">
<label asp-for="SysInfo.AgentID" class="control-label"></label>
<select asp-for="SysInfo.AgentID" class="form-control" asp-items="@Model.AgentNameSL"></select>
</div>
<div class="form-group">
<label asp-for="FileUpload.FormFile"></label>
<input asp-for="FileUpload.FormFile" type="file">
</div>
<div class="form-group">
<input class="btn btn-primary" type="submit" value="Create">
</div>
</form>
</div>
</div>```
CS
public async Task<IActionResult> OnPostAsync()
using (var memoryStream = new MemoryStream())
await FileUpload.FormFile.CopyToAsync(memoryStream);
SysInfo.Content = memoryStream.ToArray();
if (!ModelState.IsValid)
return Page();
_context.SysInfo.Add(SysInfo);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
【讨论】:
很好地解决了这个问题。就在几周前,我遇到了一个非常相似的问题。 IFormFile 不断返回 null。我可以通过我在发布的答案中所做的事情来获得它。【参考方案2】:您可以通过一种简单的方式在您的剃须刀页面中使用此 html:
<form enctype="multipart/form-data" method="post">
<dl>
<dt>
<label>Choose File</label>
</dt>
<dd>
<input name="file" type="file">
</dd>
</dl>
<input asp-page-handler="Upload" class="btn btn-info btn-block" type="submit" value="Upload" />
</form>
然后在页面模型中的 OnPostUpload 方法中,只需将 IFormFile 文件作为参数传递:
public IActionResult OnPostUpload(IFormFile file)
【讨论】:
以上是关于在 Razor 页面上使用选择列表和文件上传的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 ASP.NET Core Razor 页面预选下拉列表中的项目
在 post .net Core Razor 页面上与数据绑定模型作斗争