views:

28

answers:

2

This is mostly theoretical question, since I actually can implement it in any way, but it confuses me a bit. So, suppose I present a user with a page to select an Excel file, which is then uploaded to the server. Server code parses the file, and presents the user with another page with many options. The user can select and deselect some of them, edit names, and then click OK - after which the server has to process only the selected options.

The question may be:

  • is it better to store parsed file in Session?
  • is it better to push parsed data to client's page and then receive it back?

Here's example:

public class Data
{
   public string Name { get; set; } // shown to user, can be changed
   public bool Selected { get; set; } // this is in ViewModel but anyway
   public string[] InternalData { get; set; } // not shown to user
}

// 1st option is to receive data via POST
public ActionResult ImportConfirmed(IList<Data> postitems)
{
   // 2nd option is to receive only user changes via POST
   var items = Session["items"] as IList<Data>;
   items = items.Where(postitems of same name selected);
   items.ForEach(set name to postitems name);
}

Obviously option #2 has less side effects, since it does not have global state. But in option #1 we don't push loads of useless-to-user data to the client. And this can be a lot.

Of course this problem is not new, and as always, the answer is: it depends.

I have to admit, I don't have any exact question in mind. I can't even tell why I don't like the Session solution which takes only couple of additional lines of code. The reason I ask is that I've read about Weblocks concept and was very impressed. So, I tried to invent something similar in ASP.NET MVC and failed to. Thus, I wonder, is there any elegant way to deal with such situations? By elegant I mean something that doesn't show it uses Session, easy to use, handles expirations (cleans up the Session if user does not press the final "Save" button), etc. Something like:

var data = parse(filestream);
var confirmationPostData = ShowView("Confirm", data);
items = items.Where(confirmationPostData of same name selected);
items.ForEach(set name to confirmationPostData name);

Here ShowView actually sends GET, wait for user's POST, and returns. Kind of. I do not insist, I just show the way that impressed me (in Weblocks - if I actually did understand it correctly).

Does everyone just use Session in such cases? Or is there a better way (except learning LISP which I already started to investigate if I can cope with)? Maybe, async actions in MVC v2 do it?

UPDATE: storing in DB/temp files, it works. I do sometimes store in DB. However this needs a way to expire the data since user may just abandon it (as simple as closing the browser). What I'm asking for: is there a proven and elegant way to solve it - not about how to do it. An abstraction built on top of serialization not tied to particular DB/file implementation, something like this.

+2  A: 

I'm not sure what the purpose of uploading the Excel file is, but I like to make all actions that affect the long term state of the application, for the user, persisted. For example, what if the user uploads the file, changes a couple of options, then goes to lunch. If you store the info in session, it may be gone when they get back, ditto for storing it in the page with hidden variables. What about storing it in a DB?

Josh Pearce
I agree, I would persist the data to the db and show a summary screen with records imported and errors. with another screen which retrieves the name and lets the user select it for further processing, keep the internal data in the db.
Decker97
Pushing maybe megabyte of data to the page is really bad idea sometimes. And then user just closes the browser (or it crashes) - will the data stay in DB forever? Yes there're ways to track it - I do it myself - but is there any common way or library so that one thousand programmers do not reinvent this every day?
queen3
A: 

I would store the file at the temp folder and only associate the name of the file with the user session so that later it can be processed:

// Create a temp file in the Temp folder and return its name:
var tempFile = Path.GetTempFileName();
// write to the temp file and put the filename into the session
// so that the next request can fetch the file and process it

There's a flaw with the GetTempFileName that I once fell into because I didn't read the documentation carefully. It says that the method will start throwing exceptions if you have more than 65535 files in the temp folder. So remember to always delete the temp file once you've finished processing it.

Another alternative to the temp folder would be to store the file into a database, but I am a little skeptic about storing files inside a relational database.

Darin Dimitrov
See update. As for files, as I said it's about parsing the data, so actually data structures are to be stored - that is IList<Data>. But it doesn't really matter.
queen3