为什么字符串在 Model 和 HiddenFor 中发送,而不以 'Resubmit' 形式返回(post 手动验证错误)

Why is string sent down on Model and in HiddenFor, Not coming back up in form 'Resubmit' (post manual validation error)

我不明白为什么我在模型上设置的变量会下降到视图,但不会返回。它 'feels' 就像 HiddenFor()

中的一个奇怪错误

我写了一个重现问题的简单示例:

型号:

public class SampleModel
{
    public string SpecialString { get; set; }
    public string FileString { get; set; }
}

查看:

@model FormResubmitTest.Test.SampleModel
....
@using (Html.BeginForm())
{
    @Html.ValidationSummary(false)
    if (@Model.FileString != null)
    {
        <p>@Model.FileString file exists</p>
    }
    <div>
        @(Html.Kendo().Upload()
            .Name("uploadDocument")
            .Multiple(false)
            .ShowFileList(true)
            .Messages(o => o.Select("Select File To upload"))
        )
    </div>
    @Html.HiddenFor(model => model.FileString)
    @Html.TextBoxFor(model => model.SpecialString)
    <input type="submit" name="submit" value="Submit" />
}

控制器:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new SampleModel(){});
    }

    [HttpPost]
    public ActionResult Index(SampleModel model, HttpPostedFileBase uploadDocument)
    {
        if (uploadDocument != null)
        {
            model.FileString = SaveToTemporaryFile(uploadDocument);
        }
        if (model.SpecialString != "Special")
        {
            ModelState.AddModelError("SpecialString", "Special string was not special");
        }
        if (uploadDocument == null && model.FileString == null)
        {
            ModelState.AddModelError("FileString", "You have not uploaded a file");
        }
        if (ModelState.IsValid)
        {
            return RedirectToAction("Success");
        }
        return View(model);
    }

    public string SaveToTemporaryFile(HttpPostedFileBase file)
    {
        if (file == null)
        {
            return null;
        }
        var path = Path.GetTempPath();
        var folder = Path.Combine(path, Guid.NewGuid().ToString());
        Directory.CreateDirectory(folder);
        var fileName = file.FileName;
        fileName = System.IO.Path.GetFileName(fileName) ?? "file.txt";
        var fullFileName = Path.Combine(folder, fileName);
        using (FileStream fileStream = System.IO.File.Create(fullFileName, (int)file.InputStream.Length))
        {
            byte[] bytesInStream = new byte[file.InputStream.Length];
            file.InputStream.Read(bytesInStream, 0, bytesInStream.Length);
            fileStream.Write(bytesInStream, 0, bytesInStream.Length);
        }
        return fullFileName;
    }
}

查看错误:

我不明白为什么在第二次调用时,模型有一个空白文件字符串。现在,如果我查看生成代码的隐藏,它非常清楚,值是空白!

<input id="FileString" name="FileString" type="hidden" value="" />

我已经把完整的写在下面了,可是为什么它的值是空的!!?从生成的消息我们可以看出;服务器在生成时就知道它....我很困惑!

---编辑---

我可以这样做:

<input id="FileString" name="FileString" type="hidden" value="@Model.FileString" />

而不是

@Html.HiddenFor(model => model.FileString)

但我必须这样做似乎是错误的

MVC(或者我应该说的 Html 库)是否以某种方式记住了原始发布的值?并在 "Fors"

中使用它们

您需要将 hiddenFor 移到 beginform 之外。我通常将所有这些放在顶部。 beginform 中的任何内容都会在 re-post 上重新呈现,这就是为什么 hiddenfor 不会被填充的原因,因为在此内部,所有内容都被视为刷新的表单。

隐藏元素通常用作在表单之间传递值的方式(比将其放在查询字符串上更好)。如果要传递的表单值开始太多,那么通常我们会开始引入其他 javascript 库,例如 Angular,它也使用 MVC 模式在表单周围移动我们的对象,因为这通常更干净只要 Angular 或其他库正确实现即可。

您看到的行为是设计使然。所有生成表单控件的 HtmlHelper 方法(PasswordFor() 除外)使用来自 ModelState 的值(如果它们存在),然后来自 ViewDataDictionary,然后来自模型 属性.

第一次生成视图时,ModelState还没有加值,FileString的值为null,所以生成<input ... value="" />

当您提交表单时,模型中每个 属性 的值都会由 DefaultModelBinder 添加到 ModelState(对于 FileString,其值为 null)。然后修改 FileString 和 return 视图的值。

HiddenFor() 方法现在在 ModelState 中找到 null 的值并再次生成 <input ... value="" />(在 POST 方法中设置值不会覆盖 ModelState).

中的值

如果你想 return 不同的视图,那么你应该遵循 PRG 模式并重定向,但是你可以通过从 ModelState 中删除值来解决这个问题,所以 HiddenFor() 方法使用模型中的值。

您可以使用

清除ModelState中的所有值
ModelState.Clear()

或删除 ModelState 仅一个 属性 使用

ModelState.Remove("FileString");