在 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 页面上与数据绑定模型作斗争

如何在不更改页面的情况下上传文件

Confluence 6 上传文件

asp.net Razor Pages - 根据另一个选择列表的选择更新选择列表

如何上传文件