6

Good morning - I am attempting to save an HttpPostedFileBase (which will always be a simple CSV file) to a session variable like so:

    [HttpPost]
    public ActionResult Index(HttpPostedFileBase importFile) {
        Session.Remove("NoteImport");
        var noteImport = new NoteImport { ImportFile = importFile, HeaderList = NoteService.HeaderList(importFile) };
        Session["NoteImport"] = noteImport;
        return RedirectToAction("FileNote");

    }

As you see, I am dumping importFile into my NoteImport class. Currently, the ImportFile property is a publicly accessible HttpPostedFileBase type.

The first time I use this property in my service (method that creates a list of header values), I have no problem:

    public List<string> HeaderList(HttpPostedFileBase fileStream) {
        var sr = new StreamReader(fileStream.InputStream);
        var headerString = sr.ReadLine();
        var headerArray = headerString.Split(',');
        var headerList = new List<string>();
        foreach (var header in headerArray) {
            if (!ValidateHeader(header))
                throw new InvalidDataException("Invalid header name: " + header);
            headerList.Add(header);
        }
        return headerList;
    }

The above works fine and returns exactly what I need for the time being.

My problem is with the code below. When I call ReadLine(), it doesn't get anything out of the HttpPostedFileBase.

    public List<string> ImportFileStream(HttpPostedFileBase importFile) {
        var sr = new StreamReader(importFile.InputStream);
        var headerString = sr.ReadLine();
        var headerArray = headerString.Split(',');
        var cb = new DelimitedClassBuilder("temp", ",") { IgnoreFirstLines = 0, IgnoreEmptyLines = true, Delimiter = "," };
        foreach (var header in headerArray) {
            cb.AddField(header, typeof(string));
            cb.LastField.FieldQuoted = true;
            cb.LastField.QuoteChar = '"';
        }
        var engine = new FileHelperEngine(cb.CreateRecordClass());
        var dataTable = engine.ReadStreamAsDT(sr);
        var noteData = new List<string>();
        var jsonSerializer = new JsonSerializeDataRow();
        foreach (var row in dataTable.Rows) {
            var dataRow = row as DataRow;
            var jsonRow = jsonSerializer.Serialize(dataRow);
            noteData.Add(jsonRow);
        }
        return noteData;
    }

I have attempted closing the HttpPostedFileBase; I have also set the stream position to 0. Nothing seems to be going. I have a feeling I need to change it to a different type before saving to the session.

Any advice??

Thanks!

BueKoW
  • 916
  • 4
  • 18
  • 33

3 Answers3

5

You cannot store an HttpPostedFileBase into the session. This just doesn't make sense. It contains a stream pointing to the file contents from the HTTP Request stream which is garbage collected at the end of the request. You need to serialize it to some custom object before storing into session. For example:

public class MyFile
{
    public string Name { get; set; }
    public string ContentType { get; set; }
    public byte[] Contents { get; set; }
}

Now go ahead and store this into the session. Of course you should be aware that by doing this you are storing the entire file contents into memory which might not be something you want to do especially if the uploaded files can be large. Another possibility is to store the file contents into the persistable media like a disk or database and store into session only a pointer to this media so that you can retrieve it later.

Darin Dimitrov
  • 960,118
  • 257
  • 3,196
  • 2,876
  • perfect - thanks! The functionality this is for will be used once per day at best (currently, we probably use it once/every-other-week and the largest CSV file we've used to manually complete this operation was 55K. I figured due to the minimal use, storing in the session would be more efficient than writing out to a temp file. Would you agree? – BueKoW Jan 20 '11 at 13:56
  • @BueKoW, yes file size seems acceptable for storing into session. – Darin Dimitrov Jan 20 '11 at 14:05
  • Could you share how to do this? Thanks – nfplee Feb 22 '11 at 14:06
2

if your using HttpPostedFileBase you need to clone it first,
i used the code from this git
you just need to add this as a class in your namespace:

public static class HttpPostedFileBaseExtensions
{
    public static Byte[] ToByteArray(this HttpPostedFileBase value)
    {
        if (value == null)
            return null;
        var array = new Byte[value.ContentLength];
        value.InputStream.Position = 0;
        value.InputStream.Read(array, 0, value.ContentLength);
        return array;
    }
}

now you can read the HttpPostedFileBase like so:

private static void doSomeStuff(HttpPostedFileBase file)
{
    try
    {
        using (var reader = new MemoryStream(file.ToByteArray()))
        {
            // do some stuff... say read it to xml
            using (var xmlTextReader = new XmlTextReader(reader))
            {                    

            }
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

after using this you can still write in your main code:

file.SaveAs(path);

and it will save it to the file.

Yakir Manor
  • 4,409
  • 1
  • 28
  • 24
0

HttpPostedFile reads directly from the HTTP request stream.
It is not suitable for reuse.

SLaks
  • 800,742
  • 167
  • 1,811
  • 1,896