ASP.Net MVC和状态 - 如何在请求之间保持状态

时间:2012-05-25 14:23:52

标签: asp.net-mvc action viewmodel state

作为一个刚刚开始使用MVC的相当有经验的ASP.Net开发人员,我发现自己正在努力将我的思维方式从传统的“服务器控件和事件处理程序”的做事方式转变为更加动态的MVC方式。我想我正在慢慢地到达那里,但有时MVC“魔法”会让我失望。

我目前的情况是创建一个网页,允许用户浏览本地文件,将其上传到服务器并重复此操作,直到他有一个要处理的文件列表。当他对文件列表(将在页面上的网格中显示)感到满意时,他将单击一个按钮来处理文件并提取一些将存储在数据库中的数据。

最后一部分并不那么重要,现在我正在努力处理一些像建立文件列表那样微不足道的事情,并在请求之间保持该列表。在传统方法中,这将非常简单 - 数据将保存在ViewState中。但是在MVC中,我需要在控制器和视图之间传递数据,而我并没有完全了解它应该如何工作。

我想我最好发布一个相当不完整的编码来解释这个问题。

为了保存我的文件列表数据,我创建了一个viewmodel,它基本上是一个类型化的文件列表,还有一些额外的元数据:

public class ImportDataViewModel
{
    public ImportDataViewModel()
    {
        Files = new List<ImportDataFile>();
    }

    public List<ImportDataFile> Files { get; set; }
...

在视图中,我有一个用于浏览和上传文件的表单:

<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>

视图使用viewmodel作为其模型:

@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页面的视图以及包含文件列表的viewmodel实例。

这可以很好地达到某一点,我可以浏览文件并上传它,我可以在动作中看到viewmodel数据,然后如果我在视图中放置一个断点并调试“this.Model”一切都很好。

但是,如果我尝试上传另一个文件,在AddImportFile操作中放置断点时,importData参数为空。因此,视图显然没有将其模型的当前实例传递给操作。

在我经历过的MVC示例中,模型实例被“神奇地”作为参数传递给action方法,为什么它现在为空?

我认为真正的问题是我对MVC的理解有限,并且可能有一个非常简单的解决方案。无论如何,如果有人能指出我正确的方向,我将非常感激。

2 个答案:

答案 0 :(得分:48)

自从我发布这个问题以来已经有一段时间了,我的MVC经验和知识很少。我仍然收到了一些非常有用的信息,最终让我找到了解决方案并获得了一些MVC的见解。

首先让我失望的是,您可以将控制器与强类型对象作为参数,如下所示:

public ActionResult DoSomething(MyClass myObject)...

此对象源自同一个控制器:

...
return View(myObject);
...

这让我相信这个对象贯穿了这两个步骤,并且我可以期待你可以将它发送到视图,做一些事情,然后&#34;神奇地&#34;再次回到控制器。

在阅读了关于模型绑定的内容后,我明白当然不是这种情况。该视图完全是静止的,除非您将信息存储在某处,否则它就消失了。

回到问题,即从客户端选择和上传文件,并构建要显示的这些文件的列表,我意识到通常有三种方法在MVC中的请求之间存储信息:

  1. 您可以将信息存储在视图中的表单字段中,稍后将其发布回控制器
  2. 您可以将其保留在某种存储空间中,例如:文件或数据库
  3. 您可以通过访问遍及请求的对象将其存储在服务器内存中,例如:会话变量
  4. 就我而言,我基本上有两种类型的信息要坚持:   1.文件元数据(文件名,文件大小等)   2.文件内容

    &#34; by-the-book&#34;方法可能是将元数据存储在表单字段中,将文件内容存储在文件或db中。但还有另一种方式。由于我知道我的文件非常小而且只有少数几个,而且这个解决方案永远不会部署在服务器场或类似的,我想探索会话变量的#3选项。这些文件在会话之外持久存在也没有意义 - 它们被处理和丢弃,因此我不想将它们存储在我的数据库中。

    阅读这篇优秀文章后: Accessing ASP.NET Session Data Using Dynamics

    我确信。我只是按照文章中的描述创建了一个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");
        }
    

    我完全清楚,在大多数情况下,这将是一个糟糕的解决方案。但是对于文件占用的几kb服务器内存以及所有内容的简单性,我认为它对我来说非常好。

    使用SessionBag的额外好处是,如果用户输入了不同的菜单项然后又返回,则文件列表仍然存在。例如,情况并非如此。选择表单字段/文件存储选项时。

    作为最后的评论,我意识到SessionBag很容易被滥用,因为使用简单。但是如果你将它用于它的意图,即会话数据,我认为它可以是一个强大的工具。

答案 1 :(得分:11)

关于上传

1)也许考虑使用带有HTML的AJAX上传器,允许用户在将发送到服务器之前选择多个文件。这个BlueImp Jquery AJAX文件上传程序非常棒,非常棒的api:Blueimp Jquery File Upload。它将允许用户拖放或多选几个文件并编辑文件顺序,包括/排除等。然后当他们开心时,他们可以按上传发送到您的控制器或上传处理程序以便在服务器端进行处理。

2)您可以将每个上传保留到数据库,但您将重新加载整个页面并编写一些额外的视图模型和剃刀代码以实现列表效果。这可能不会响应......

关于保持状态WebForms / MVC

在请求之间保持状态有点黑魔法和伏都教。进入ASP.NET MVC时,请了解Web应用程序使用请求和响应进行通信。因此,将网络视为无国籍,并从那里发展!当您的模型通过控制器发布时,消失以及控制器中的任何变量!但是,在它消失之前,您可以将其内容存储在数据库中以便以后检索。

Web应用程序无法像桌面应用程序一样保持真实状态。有许多方法可以使用ajax框架,以及人们用来在HTTP环境中模拟状态的一些voodoo工具。对状态的模拟实际上只是对有状态的虚假模仿。 ASP.NET Web Forms尝试通过隐藏开发人员的HTTP的无状态特性来尽可能地模拟状态。当您尝试使用自己的AJAX代码以及Web Forms标记代码和自己的Ajax框架时,您可能会遇到很多麻烦。

我很高兴你学习MVC

除了所有的笑话,如果你得到MVC / HTTP /无状态心态,将模式应用到其他超级流行的框架,如Ruby on Rails,SpringMVC(java),Django(python),CakePHP等都会非常容易。 ...这种简单的知识转移将帮助您成为一个更好的开发人员,并真正擅长Ajax。

我很高兴你正在学习MVC 3,我曾经在一些非常大的公司实习,这些公司有这些疯狂的大型ASP.NET Web Forms项目,代码随处可见,只是为了改变一些数值在数据库中(-_-')感觉就像我用剪刀编织婴儿的袜子。一个容易出错的举动,一切都破了。感觉就像用PHP开发一样,你出汗了,并不确定发生了什么,在什么线上。调试和更新几乎是不可能的。