用于在ASP.NET MVC 3中上载多个文件的ViewModel

时间:2012-08-13 06:39:11

标签: asp.net-mvc-3 file-upload asp.net-mvc-viewmodel

我有多个文件上传ViewsViewModel绑定如下:

@model IVRControlPanel.Models.UploadNewsModel
  @using (Html.BeginForm("index", "NewsUpload", FormMethod.Post, new { name = "form1", @id = "form1" }))
        {
            @Html.ValidationSummary(true)

            <div class="field fullwidth">
                <label for="text-input-normal">
                    @Html.Label("Select Active Date Time")</label>
                <input type="text" id="active" value="@DateTime.Now" />
                 @Html.ValidationMessageFor(model => model.ActiveDateTime)
            </div>

            <div class="field fullwidth">
                <label>
                    @Html.Label("Select Language")
                </label>
                @Html.DropDownList("Language", (SelectList)ViewBag.lang)
            </div>

            <div class="field">
                <label>
                    @Html.Label("General News")
                </label>
               @Html.TextBoxFor(model => model.generalnews, new { name = "files", @class="custom-file-input", type = "file" })
                @Html.ValidationMessageFor(model => model.generalnews)
            </div>
            <div class="field">
                <label>
                    @Html.Label("Sports News")
                </label>
               @Html.TextBoxFor(model => model.sportsnews, new { name = "files", @class = "custom-file-input", type = "file" })
                @Html.ValidationMessageFor(model => model.sportsnews)
            </div>         
            <div class="field">
                <label>
                    @Html.Label("Business News")
                </label>
               @Html.TextBoxFor(model => model.businessnews, new { name = "files", @class = "custom-file-input", type = "file" })
                @Html.ValidationMessageFor(model => model.businessnews)
            </div>            
            <div class="field">
                <label>
                    @Html.Label("International News")
                </label>
               @Html.TextBoxFor(model => model.internationalnews, new { name = "files", @class = "custom-file-input", type = "file" })
                @Html.ValidationMessageFor(model => model.internationalnews)
            </div>    
             <div class="field">
                <label>
                    @Html.Label("Entertaintment News")
                </label>
               @Html.TextBoxFor(model => model.entertaintmentnews, new { name = "files", @class = "custom-file-input", type = "file" })
                @Html.ValidationMessageFor(model => model.entertaintmentnews)
            </div>          

             <footer class="pane">
                <input type="submit" class="bt blue" value="Submit" />
            </footer>                              
        }

使用数据注释查看模型,以验证允许的扩展名的文件上载,如下所示:

 public class UploadNewsModel
{
    public DateTime ActiveDateTime { get; set; }

   // public IEnumerable<SelectListItem> Language { get; set; }

    [File(AllowedFileExtensions = new string[] { ".jpg", ".gif", ".tiff", ".png", ".pdf", ".wav" }, MaxContentLength = 1024 * 1024 * 8, ErrorMessage = "Invalid File")]
    public HttpPostedFileBase files { get; set; }

}

控制器:用于保存多个文件,如果存在错误则返回视图

  [HttpPost]
            public ActionResult Index(UploadNewsModel news, IEnumerable<HttpPostedFileBase> files)
            {
                if (ModelState.IsValid)
                {
                    foreach (var file in files)
                    {
                        if (file != null && file.ContentLength > 0)
                        {
                            var fileName = Path.GetFileName(file.FileName);
                            var serverpath = Server.MapPath("~/App_Data/uploads/News");
                            var path = Path.Combine(serverpath, fileName);
                            if (!Directory.Exists(serverpath))
                            {
                                Directory.CreateDirectory(serverpath);
                            }

                            file.SaveAs(path);
                        }

                    }
                }
                return View(news);
            }

        }

问题解释 如何为这五个文件上传输入控件定义视图模型,以便在不允许上传文件的文件扩展名时显示相应的验证错误相应的错误。对于所有五个文件上传控件,我只有一个视图模型项。

为那些多文件上传控件定义视图模型的最佳方法是显示相应的验证错误,而不是用户尝试上传不允许的扩展名的文件???

1 个答案:

答案 0 :(得分:2)

这里真正的问题是MVC没有适合http文件的模型绑定器。

因此,除非你使用像mvc期货那样对文件上传有一些额外支持的项目,你将不得不得到一些脏东西并自己努力工作。

以下是一个可能对您有所帮助的示例。

首先,我会创建一个ViewModel来表示一个这样的文件:

public class FileViewModel
{  
    public Guid Id { get; set; }
    public string Name { get; set; }
    public bool Delete { get; set; }
    public string ExistingUrl { get; set; }

    public HttpPostedFileBase FileBase { get; set; }
}

显然,属性取决于您的要求,重要的是FileBase,它是自己的模型。

接下来,您网页的ViewModel(在您的情况下为UploadNewsModel):

public class IndexViewModel
{ 
    public IList<FileViewModel> Files { get; set; }
}

这里的重要部分是IList of Files,这就是我们捕获多个文件的方式(在你当前的'file'实现中你只捕获一个文件。

在页面级视图上

@model IndexViewModel
<form method="post" action="@Url.Action("Index")" enctype="multipart/form-data">
@Html.ValidationSummary(true)
@Html.EditorFor(x => x.Files)
<input type="submit" value="Submit" />
</form>

注意 EditorFor ,我们接下来要做的是为 FileViewModel 创建一个 EditorTemplate ,此时应该使用它。

喜欢这样:

@model FileViewModel

<h4>@Model.Name</h4>
@Html.HiddenFor(x => x.Id)
@Html.CheckBoxFor(x => x.Delete)

<input @( "name=" + ViewData.TemplateInfo.HtmlFieldPrefix + ".FileBase") type="file" />

注意 ViewData.TemplateInfo.HtmlFieldPrefix 的用法,它有点糟糕,但我说这是因为mvc对文件输入类型的支持很差。我们必须自己做。我们除了每个文件的名称之外都是'[0] .FileBase'等。

这将在POST操作上正确填充 FileViewModel

到目前为止很好,验证怎么样?

再次,您可以在服务器上手动执行此操作。自己测试文件扩展名,只需使用以下内容将错误添加到模型中,如:

ModelState.AddModelError("","Invalid extension.")

另一方面,扩展验证应该在客户端(以及服务器端)进行