1

我不明白为什么我在模型上设置的变量会下降到视图中,但不会重新出现。它的“感觉”就像一个奇怪的错误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;
    }
}

要查看错误:

  • 上传一个文件
  • 输入一个非“特殊”的字符串
  • 点击提交
  • 现在它将正确显示 FileString
  • 输入“特别”
  • 点击提交
  • 函数 Index 将有一个带有空白 FileString的模型

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

<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”中使用它们

4

2 回答 2

1

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

当您第一次生成视图时,没有向 中添加任何值ModelState,并且 的值FileStringnull这样生成的<input ... value="" />

当您提交表单时,模型中每个属性的值ModelState都由DefaultModelBinder(在 的情况下FileString,其值为null)相加。然后修改 的值FileString并返回视图。

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

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

ModelState您可以从使用中清除所有值

ModelState.Clear()

或使用仅删除ModelState一个属性

ModelState.Remove("FileString");
于 2017-12-18T21:24:35.850 回答
0

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

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

于 2017-12-18T16:37:02.807 回答