ASP.Net MVC and state - how to maintain state between requests

As a fairly experienced ASP.Net developer who recently started using MVC, I try to change my thinking a bit with the traditional “server and event handler” management method in a more dynamic way of MVC. I think I get there slowly, but sometimes MVC "magic" casts me away.

My current scenario is to create a web page that allows the user to view the local file, upload it to the server, and repeat this until it has a list of files to work with. When he is satisfied with the list of files (which will be displayed in the grid on the page), he will click a button to process the files and extract some data that will be stored in the database.

The last part is not so important, now I'm struggling with something as trivial as creating a list of files and saving this list between requests. In a traditional approach, this would be extremely simple - data would be stored in the ViewState. But in MVC, I need to transfer data between the controller and the views, and I do not fully understand how this should work.

I think I'd rather post my rather incomplete attempt to encode this to explain the problem.

To save the file list data, I created a view model, which is a typed file list, as well as some additional metadata:

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

In the view, I have a form for viewing and downloading a 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 uses the viewmodel as its model:

 @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 a view for the DataImport page along with a viewmodel instance containing a list of files.

This works well until a certain point, I can view the file and load it, and I can see the viewmodel data inside the action, and then also, if I put a breakpoint in the view and debug "this.Model", everything is fine.

But then, if I try to load another file, when setting a breakpoint inside the AddImportFile action, the importData parameter is empty. Thus, the view obviously does not pass the current instance of its model to the action.

In the MVC samples I went with, an instance of the model is “magically” passed to the action method as a parameter, so why is it now empty?

I assume the real problem is my limited understanding of MVC and that this is probably a very simple solution. In any case, I would be extremely grateful if someone could point me in the right direction.

+46
asp.net-mvc state viewmodel action
May 25 '12 at 14:23
source share
2 answers

It has been some time since I posted a question that was pretty colored by my little experience and knowledge of MVC. However, I received a rather useful contribution, which ultimately led me to find a solution, as well as get some idea about MVC.

What threw me away in the first place was that you could have a controller with a strongly typed object as a parameter, for example:

 public ActionResult DoSomething(MyClass myObject)... 

This object originated from the same controller:

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

This led me to believe that the object lived during these two steps, and that somehow I could expect that you could send it to the view, do something, and then "magically" return it back to the controller.

After familiarizing myself with the binding to the model, I realized that this, of course, is not so. The look is completely dead and static, and if you do not store information somewhere, it will disappear.

Returning to the problem that selected and downloaded files from the client, and creating a list of these files for display, I realized that in general there are three ways to store information between requests in MVC:

  • You can store information in the form fields in the view and send it to the controller later
  • You can save it in some kind of storage, for example. file or database
  • You can save it in server memory using objects that reside in all requests, for example. session variables

In my case, I had basically two types of information that I needed to save: 1. File metadata (file name, file size, etc.). 2. File Contents

The book-based approach is likely to be to store metadata in the form fields and the contents of the file in a file or in db. But there is another way. Since I know that my files are quite small and there will be only a few, and this solution will never be deployed in a server farm or similar, I would like to examine the parameter # 3 of session variables. Files are also not interesting for saving outside the session - they are processed and discarded, so I did not want to store them in my db.

After reading this great article: Accessing ASP.NET Session Data Using Dynamics

I was convinced. I just created the sessionbag class as described in the article, and then I could do the following in my 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"); } 

I understand perfectly well that in most cases this would be a bad decision. But for a few kilobytes of server memory, the files take up and with the simplicity of all this, I think it worked very well for me.

An additional bonus of using SessionBag is that if the user entered another menu item and then returned, the list of files will still be there. This is not the case, for example. when choosing the form / file field.

To conclude, I understand that SessionBag is very easy to abuse, given its ease of use. But if you use it for what it is intended for, namely for session data, I think it can be a powerful tool.

+46
Jun 03 '12 at 18:23
source share

Regarding the download

1) Perhaps consider the AJAX HTML loader to allow your user to select multiple files before sending them to the server. This BlueImp JQuery AJAX download is pretty fun with a pretty big api: Download Blueimp Jquery . This will allow users to drag and drop or select multiple files and change the order of files, include / exclude, etc. Then, when they are happy, they can click the Download button to send to the controller or download handler for server-side processing.

2) You can make each download saved in the database, although you would reload the entire page and write an additional view model and razor code to achieve the listing effect. This probably won't respond ...

Regarding maintaining state of WebForms / MVC

Saving state between requests is a bit of black magic and voodoo. When you enter ASP.NET MVC, understand that it understands that web applications communicate using requests and responses. So keep embracing the network as stateless and evolve from there! When your model is sent through your controller, it is gone along with any variables in the controller! However, before it leaves, you can save its contents in a database for later retrieval.

Web applications cannot maintain true state, such as desktop applications. There are many ways to create ajax frameworks and some voodoo tools that people use to model state in an HTTP environment. And the simulation of the state is just a false facial expression. ASP.NET Web Forms attempts to simulate state as much as possible by hiding HTTP statelessness from the developer. You may run into a big headache when trying to use your own AJAX code in tandem with Web Forms markup code and your own Ajax framework.

I am very glad that you are learning MVC

All jokes aside, if you get the MVC / HTTP / stateless mentality, it will be very easy to apply templates 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 in Ajax.

I'm really glad that you study MVC 3, I was with several internships at some very large companies that had these crazy large ASP.NET Web Forms projects with code that flew everywhere to change a few numerical values ​​in the database (- _- ') Felt, as if I used scissors to knit a baby sock. One simple wrong move, and everything broke. It was like development in PHP, you get out of the pot and are not quite sure what happened and on which line. Debugging and updating was almost impossible.

+10
May 25 '12 at 14:45
source share



All Articles