asp.net-mvc ASP.Net MVC 和状态 - 如何在请求之间保持状态
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10756140/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ASP.Net MVC and state - how to keep state between requests
提问by TMan
As a fairly experienced ASP.Net developer just recently starting using MVC, I find myself struggling a bit to change my mindset from a traditional "server control and event handler" way of doing things, into the more dynamic MVC way of things. I think I am slowly getting there, but sometimes the MVC "magic" throws me off.
作为一个刚刚开始使用 MVC 的相当有经验的 ASP.Net 开发人员,我发现自己在将我的思维方式从传统的“服务器控制和事件处理程序”的做事方式转变为更动态的 MVC 做事方式方面遇到了一些困难。我想我正在慢慢地到达那里,但有时 MVC 的“魔法”让我望而却步。
My current scenario is to create a web page that allows the user to browse a local file, upload it to the server and repeat this until he has a list of files to work with. When he is happy with the file list (which will be displayed in a grid on the page), he will click a button to process the files and extract some data that will be stored in a database.
我当前的方案是创建一个网页,允许用户浏览本地文件,将其上传到服务器并重复此操作,直到他拥有要使用的文件列表。当他对文件列表(将显示在页面上的网格中)感到满意时,他将单击一个按钮来处理文件并提取一些将存储在数据库中的数据。
The last part is not so important, right now I am struggling with something as trivial as building up a list of files, and persisting that list between requests. In the traditional approach this would be extremely simple - the data would be persisted in ViewState. But in MVC I need to pass the data between the controller and the views, and I don't fully get how this is supposed to work.
最后一部分不是那么重要,现在我正在努力处理一些像构建文件列表这样微不足道的事情,并在请求之间保留该列表。在传统方法中,这将非常简单——数据将保存在 ViewState 中。但是在 MVC 中,我需要在控制器和视图之间传递数据,而且我不完全了解它应该如何工作。
I guess I better post my rather incomplete attempt of coding this to explain the problem.
我想我最好发布我相当不完整的编码尝试来解释这个问题。
In order to keep my file list data, I have created a viewmodel that is basically a typed list of files, along with some extra metadata:
为了保留我的文件列表数据,我创建了一个视图模型,它基本上是一个类型化的文件列表,以及一些额外的元数据:
public class ImportDataViewModel
{
public ImportDataViewModel()
{
Files = new List<ImportDataFile>();
}
public List<ImportDataFile> Files { get; set; }
...
In the view, I have a form for browsing and uploading the file:
在视图中,我有一个用于浏览和上传文件的表单:
<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>
The view is using the viewmodel as its model:
该视图使用 viewmodel 作为其模型:
@model MHP.ViewModels.ImportDataViewModel
This will send the file to my action:
这会将文件发送到我的操作:
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);
}
This action returns the view for the DataImport page along with the viewmodel instance containing the list of files.
此操作返回 DataImport 页面的视图以及包含文件列表的视图模型实例。
This works nicely up to a certain point, I can browse a file and upload it, and I can see the viewmodel data inside the action, and then also if I put a breakpoint inside the view and debug "this.Model", everything is fine.
这在某个点上效果很好,我可以浏览一个文件并上传它,我可以看到动作中的视图模型数据,然后如果我在视图中放置一个断点并调试“this.Model”,一切都是美好的。
But then, if I try to upload another file, when putting a breakpoint inside the AddImportFile action, the importData parameter is empty. So the view is obviously not passing the current instance of its model to the action.
但是,如果我尝试上传另一个文件,当在 AddImportFile 操作中放置断点时,importData 参数为空。所以视图显然没有将其模型的当前实例传递给动作。
In the MVC samples I have been through, the model instance is "magically" passed to the action method as a parameter, so why is it empty now?
在我经历过的 MVC 示例中,模型实例“神奇地”作为参数传递给 action 方法,为什么现在它是空的?
I assume the real problem is my limited understanding of MVC, and that there is probably a very simple solution to this. Anyways, I would be extremely grateful if somebody could point me in the right direction.
我认为真正的问题是我对 MVC 的理解有限,并且可能有一个非常简单的解决方案。无论如何,如果有人能指出我正确的方向,我将不胜感激。
采纳答案by TMan
It's been some time since I posted the question, which was quite colored by my little experience and knowledge of MVC. Still I received some quite useful input, that eventually led me to find a solution and also gain some insight of MVC.
自从我发布问题以来已经有一段时间了,由于我对 MVC 的一点经验和知识,这个问题非常有色彩。我仍然收到了一些非常有用的输入,最终让我找到了一个解决方案,并且对 MVC 有了一些了解。
What threw me off in the first place, was that you could have a controller with a strongly typed object as a parameter, like this:
首先让我失望的是,你可以有一个带有强类型对象作为参数的控制器,如下所示:
public ActionResult DoSomething(MyClass myObject)...
This object originated from the same controller:
这个对象来自同一个控制器:
...
return View(myObject);
...
This lead me to believe that the object lived throughout these two steps, and that I somehow could expect that you could send it to the view, do something and then "magically" get it back to the controller again.
这让我相信对象在这两个步骤中一直存在,并且我可以以某种方式期望您可以将它发送到视图,执行某些操作然后“神奇地”再次将其返回到控制器。
After reading up about model binding, I understood that this is of course not the case. The view is completely dead and static, and unless you store the information somewhere, it is gone.
在阅读了模型绑定之后,我明白这当然不是这种情况。视图完全是死的和静态的,除非你将信息存储在某个地方,否则它就消失了。
Going back to the problem, which was selecting and uploading files from the client, and building up a list of these files to be displayed, I realized that in general there are three ways to store information between requests in MVC:
回到问题,从客户端选择和上传文件,并建立要显示的这些文件的列表,我意识到在 MVC 中,通常有三种方法可以在请求之间存储信息:
- You can store information in form fields in the view, and post it back to the controller later
- You can persist it in some kind of storage, e.g. a file or a database
- You can store it in server memory by acessing objects that lives throughout requests, e.g. session variables
- 您可以将信息存储在视图中的表单字段中,稍后将其发回控制器
- 您可以将其保存在某种存储中,例如文件或数据库
- 您可以通过访问存在于整个请求中的对象(例如会话变量)将其存储在服务器内存中
In my case, I had basically two types of information to persist: 1. The file metadata (file name, file size etc.) 2. The file content
就我而言,我基本上有两种类型的信息要保留:1. 文件元数据(文件名、文件大小等) 2. 文件内容
The "by-the-book" approach would probably be to store the metadata in form fields, and the file contents in a file or in db. But there is also another way. Since I know my files are quite small and there will be only a few of them, and this solution will never be deployed in a server farm or similar, I wanted to explore the #3 option of session variables. The files are also not interesting to persist beyond the session - they are processed and discarded, so I did not want to store them in my db.
“按书”方法可能是将元数据存储在表单字段中,并将文件内容存储在文件或数据库中。但也有另一种方式。由于我知道我的文件很小而且只有几个,而且这个解决方案永远不会部署在服务器场或类似的地方,我想探索会话变量的 #3 选项。这些文件也没有兴趣在会话之外保留 - 它们被处理和丢弃,所以我不想将它们存储在我的数据库中。
After reading this excellent article: Accessing ASP.NET Session Data Using Dynamics
阅读这篇优秀文章后: Accessing ASP.NET Session Data Using Dynamics
I was convinced. I simply created a sessionbag class as described in the article, and then I could do the following in my controller:
我被说服了。我只是按照文章中的描述创建了一个 sessionbag 类,然后我可以在我的控制器中执行以下操作:
[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");
}
I am fully aware that in most cases, this would be a bad solution. But for the few kb of server memory the files occupy and with the simplicity of it all, I think it worked out very nicely for me.
我完全知道在大多数情况下,这将是一个糟糕的解决方案。但是对于文件占用的几 kb 服务器内存,并且由于这一切都很简单,我认为它对我来说效果很好。
The additional bonus of using the SessionBag is that if the user entered a different menu item and then came back, the list of files would still be there. This would not be the case e.g. when choosing the form fields/file storage option.
使用 SessionBag 的额外好处是,如果用户输入不同的菜单项然后返回,文件列表仍然存在。例如,在选择表单字段/文件存储选项时,情况并非如此。
As a final remark, I realize that the SessionBag is very easy to abuse, given the simplicity of use. But if you use it for what it is meant for, namely session data, I think it can be a powerful tool.
最后,我意识到 SessionBag 很容易被滥用,因为它使用起来很简单。但是如果你将它用于它的目的,即会话数据,我认为它可以成为一个强大的工具。
回答by Max Alexander
Regarding Uploading
关于上传
1) Maybe consider an AJAX uploader with HTML to allow your user to select multiple files beforethey are sent to the server. This BlueImp Jquery AJAX file uploader is pretty amazing with a pretty great api: Blueimp Jquery File Upload. It'll allow users to drag and drop or multi select several files and edit the file order, include/exclude etc.. Then when they are happy they can press upload to sent to your controller or upload handler for processing on the server side.
1)也许可以考虑使用带有 HTML 的 AJAX 上传器,以允许您的用户在将多个文件发送到服务器之前选择多个文件。这个 BlueImp Jquery AJAX 文件上传器非常棒,有一个非常棒的 api:Blueimp Jquery File Upload。它将允许用户拖放或多选多个文件并编辑文件顺序,包含/排除等。然后当他们满意时,他们可以按上传发送到您的控制器或上传处理程序以在服务器端进行处理。
2) You could make every upload persist to the database, though you would be reloading the entire page and writing some extra view model and razor code to achieve the listing effect. This is probably not going to be responsive...
2) 你可以让每次上传都持久化到数据库中,尽管你会重新加载整个页面并编写一些额外的视图模型和剃刀代码来实现列表效果。这可能不会响应......
Regarding Keeping State WebForms/MVC
关于保持状态 WebForms/MVC
Keeping state between requests is somewhat black magic and voodoo. When going into ASP.NET MVC, go in it understanding that web applications communicate using request and responses. So go in embracing the web as stateless and develop from there! When your model is posted through your controller, it's gonealong with any variables in the controller! However before it goes away, you can store its contents in a database for retrieval later.
在请求之间保持状态有点黑魔法和巫术。当进入 ASP.NET MVC 时,了解 Web 应用程序使用请求和响应进行通信。因此,将网络视为无状态并从那里进行开发!当您的模型通过您的控制器发布时,它与控制器中的任何变量一起消失了!但是,在它消失之前,您可以将其内容存储在数据库中以供以后检索。
Web applications cannot keep true state like desktop applications. There are many ways ajax frameworks, and some voodoo tools that people employ to simulate state in the HTTP environment. And a simulation of state is really only a false mimicry of statefulness. ASP.NET Web Forms tries to simulate state as best it can by kind of hiding the stateless nature of HTTP from the developer. You can run into a lot of headache when trying to employ your own AJAX code in tandem with Web Forms markup code and its own Ajax framework.
Web 应用程序无法像桌面应用程序那样保持真实状态。ajax 框架有多种方式,人们使用一些巫毒工具来模拟 HTTP 环境中的状态。状态的模拟实际上只是对状态的错误模拟。ASP.NET Web 窗体试图通过对开发人员隐藏 HTTP 的无状态特性来尽可能地模拟状态。在尝试将自己的 AJAX 代码与 Web 窗体标记代码及其自己的 Ajax 框架结合使用时,您可能会遇到很多麻烦。
I'm really glad you're learning MVC
我真的很高兴你正在学习 MVC
All jokes aside, if you get the MVC/HTTP/Statelessness mentality, it'll be very easy to apply the patterns to other super popular frameworks like Ruby on Rails, SpringMVC (java), Django (python), CakePHP etc... This easy transfer of knowledge will help you become a much better developer and get REALLY good at Ajax.
抛开所有的笑话,如果你有 MVC/HTTP/无状态的心态,那么将这些模式应用到其他超级流行的框架中会很容易,比如 Ruby on Rails、SpringMVC (java)、Django (python)、CakePHP 等等……这种轻松的知识转移将帮助您成为更好的开发人员并真正擅长 Ajax。
I'm really glad you're learning MVC 3, I've been with a few internship at some very large firms that had these crazy large ASP.NET Web Forms projects with code flying everywhere just to change a few numerical values in the database (-_-') Felt like I was using scissors to knit a baby's sock. One easy wrong move, and everything broke. It felt like developing in PHP, you come out sweating and not really sure what happened and on what line. It was almost impossible to debug and update.
我真的很高兴你正在学习 MVC 3,我曾在一些非常大的公司实习过,这些公司拥有这些疯狂的大型 ASP.NET Web 窗体项目,代码到处都是,只是为了改变数据库中的一些数值(-_-') 感觉就像我在用剪刀编织婴儿的袜子一样。一个简单的错误举动,一切都破裂了。感觉就像用 PHP 开发一样,你出来时大汗淋漓,并不确定发生了什么以及在哪条线上。调试和更新几乎是不可能的。

