作为一名相当有经验的 ASP.Net 开发人员,最近刚刚开始使用 MVC,我发现自己在努力将自己的思维方式从传统的“服务器控制和事件处理程序”做事方式转变为更动态的 MVC 做事方式。我想我正在慢慢地实现这一目标,但有时 MVC 的“魔力”让我感到困惑。
我当前的方案是创建一个网页,允许用户浏览本地文件,将其上传到服务器并重复此操作,直到获得可使用的文件列表。当他对文件列表(将显示在页面上的网格中)感到满意时,他将单击按钮来处理文件并提取一些将存储在数据库中的数据。
最后一部分并不是那么重要,现在我正在努力处理像构建文件列表以及在请求之间保留该列表这样的琐碎事情。在传统方法中,这非常简单 - 数据将保存在 ViewState 中。但在 MVC 中,我需要在 Controller 和 View 之间传递数据,但我不完全明白这是如何工作的。
我想我最好发布我相当不完整的编码尝试来解释问题。
为了保留我的文件列表数据,我创建了一个 View 模型,它基本上是一个类型化的文件列表,以及一些额外的元数据:
public class ImportDataViewModel
{
public ImportDataViewModel()
{
Files = new List<ImportDataFile>();
}
public List<ImportDataFile> Files { get; set; }
...
在 View 中,我有一个用于浏览和上传文件的表单:
<form action="AddImportFile" method="post" enctype="multipart/form-data">
<label for="file">
Filename:</label>
<input type="file" name="file" id="file" />
<input type="submit" />
</form>
View 使用 View 模型作为其模型:
@model MHP.ViewModels.ImportDataViewModel
这会将文件发送到我的操作:
public ActionResult AddImportFile(HttpPostedFileBase file, ImportDataViewModel importData)
{
if (file.ContentLength > 0)
{
ImportDataFile idFile = new ImportDataFile { File = file };
importData.Files.Add(idFile);
}
return View("DataImport", importData);
}
此操作返回 DataImport 页面的 View 以及包含文件列表的 View 模型实例。
这在某种程度上工作得很好,我可以浏览文件并上传它,并且我可以在操作中看到 View 模型数据,然后如果我在 View 中放置断点并调试“this.Model” ,一切都很好。
但是,如果我尝试上传另一个文件,则在 AddImportFile 操作中放置断点时,importData 参数为空。因此, View 显然没有将其模型的当前实例传递给操作。
在我经历过的 MVC 示例中,模型实例作为参数“神奇地”传递给了操作方法,那么为什么现在它是空的?
我认为真正的问题是我对 MVC 的理解有限,并且可能有一个非常简单的解决方案。不管怎样,如果有人能指出我正确的方向,我将非常感激。
最佳答案
我发布这个问题已经有一段时间了,由于我对 MVC 的一点经验和知识,这个问题相当有色彩。尽管如此,我还是收到了一些非常有用的意见,最终引导我找到了解决方案,并获得了一些 MVC 的见解。
首先让我失望的是,你可以有一个带有强类型对象作为参数的 Controller ,如下所示:
public ActionResult DoSomething(MyClass myObject)...
该对象源自同一 Controller :
...
return View(myObject);
...
这让我相信该对象在这两个步骤中一直存在,并且我以某种方式期望您可以将其发送到 View ,执行某些操作,然后“神奇地”再次将其返回到 Controller 。
在阅读了有关模型绑定(bind)的内容后,我明白事实并非如此。该 View 完全是死的和静态的,除非您将信息存储在某个地方,否则它就会消失。
回到问题,即从客户端选择和上传文件,并构建要显示的这些文件的列表,我意识到通常有三种方法可以在 MVC 中的请求之间存储信息:
- 您可以将信息存储在 View 中的表单字段中,并稍后将其发送回 Controller
- 您可以将其保存在某种存储中,例如文件或数据库
- 您可以通过访问整个请求期间存在的对象将其存储在服务器内存中,例如 session 变量
就我而言,我基本上有两种类型的信息需要保留: 1.文件元数据(文件名、文件大小等) 2.文件内容
“按书本”方法可能是将元数据存储在表单字段中,将文件内容存储在文件或数据库中。但还有另一种方法。因为我知道我的文件非常小,而且只有几个,而且这个解决方案永远不会部署在服务器场或类似的地方,所以我想探索 session 变量的 #3 选项。这些文件在 session 之外也没有什么意义——它们被处理和丢弃,所以我不想将它们存储在我的数据库中。
读完这篇精彩的文章后: Accessing ASP.NET Session Data Using Dynamics
我被说服了。我只是按照文章中的描述创建了一个 sessionbag 类,然后我可以在我的 Controller 中执行以下操作:
[HttpPost]
public ActionResult AddImportFile(HttpPostedFileBase file)
{
ImportDataViewModel importData = SessionBag.Current.ImportData;
if (importData == null) importData = new ImportDataViewModel();
if (file == null)
return RedirectToAction("DataImport");
if (file.ContentLength > 0)
{
ImportDataFile idFile = new ImportDataFile { File = file };
importData.Files.Add(idFile);
}
SessionBag.Current.ImportData = importData;
return RedirectToAction("DataImport");
}
我完全意识到,在大多数情况下,这将是一个糟糕的解决方案。但对于文件占用的几 kb 服务器内存以及这一切的简单性来说,我认为它对我来说效果非常好。
使用 SessionBag 的额外好处是,如果用户输入不同的菜单项然后返回,文件列表仍然存在。情况并非如此,例如选择表单字段/文件存储选项时。
最后一点,我意识到,鉴于使用的简单性,SessionBag 很容易被滥用。但如果你将它用于它的用途,即 session 数据,我认为它可以是一个强大的工具。
关于asp.net-mvc - ASP.Net MVC 和状态 - 如何在请求之间保持状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10756140/