Background of the issue.
EDIT 3 I can verify that this appears to be working again in Chrome 20. Thanks!
TLDR Update
EDIT 2 After even further mucking about this appears to be a bug in Chrome 19. Please see here:
Nothing like an up to the minute bug! :-)
Firefox-latest and IE8/9 work as expected. The Fiddler logs show the same behavior with the major difference that the 2nd 401 authorization check does not send the form payload garbled and it works as expected.
It sounds like a test case and a fix is in the works! So, hopefully for any of you out there that may have run into this, this helps!
END TLDR
I have a controller action that takes in solely an uploaded file which is a CSV file of "events". Behind the scenes, this CSV gets parsed out, turned into Event objects and the data is sync'd in the database. As a result output, the user is prompted to download an Excel spreadsheet that contains all the errors on each line that occurred.
This all works fine locally on my development machine. Once deploying to the DEV environment however, I'm getting different results. The first attempt to upload a file results in the stream being, what's the word that I'm looking for here, unreadable? It correctly reports its length but attempts to pull the information out gets nothing. Subsequent reads do have the data and everything works as expected.
I'll give to you the pertinent code pices. First, the gen'd HTML form simplified:
<form action="/Events/ImportLocal" enctype="multipart/form-data" method="post">
<input id="uploadFile" name="uploadFile" type="file" />
<input type="submit" value="Upload Events" />
</form>
Pretty straight forward:
Controller action (forgive the mess, I've been hacking at this for a couple hours now):
[HttpPost]
public ActionResult ImportLocal(HttpPostedFileBase uploadFile)
{
if (uploadFile == null || uploadFile.ContentLength <= 0)
{
BaseLogger.Info("uploadFile is null or content length is zero...");
//Error content returned to user
}
BaseLogger.InfoFormat("Community Import File Information: Content Length: {0}, Content Type: {1}, File Name: {2}",
uploadFile.ContentLength, uploadFile.ContentType, uploadFile.FileName);
//This logger line is always reporting as correct. Even on the attempts where I can't pull out the stream data, I'm seeing valid values here.
//EXAMPLE output on failed attempts:
//Import File Information: Content Length: 315293, Content Type: application/vnd.ms-excel, File Name: Export_4-30-2012.csv
BaseLogger.InfoFormat("Upload File Input Stream Length: {0}", uploadFile.InputStream.Length);
//This is reporting the correct length on failed attempts as well
//I know the below is overly complicated and convoluted but I'm at a loss for why the inputstream in HttpPostedFileBase is not pulling out as expected
//so I've been testing
var target = new MemoryStream();
uploadFile.InputStream.CopyTo(target);
byte[] data = target.ToArray();
BaseLogger.InfoFormat("File stream resulting length = {0}", data.Length);
//This reports correctly. So far so good.
StringReader stringOut;
var stream = new MemoryStream(data) {Position = 0};
using (var reader = new StreamReader(stream))
{
string output = reader.ReadToEnd();
BaseLogger.InfoFormat("Byte[] converted to string = {0}", output);
//No go...output is reported to be empty at this point so no data ever gets sent on to the service call below
stringOut = new StringReader(output);
}
//Build up a collection of CommunityEvent objects from the CSV file
ImportActionResult<Event> importActionResults = _eventImportServices.Import(stringOut);
The goal is to pass a textreader or a stringreader to the service method as behind the scenes this is using a CSV processing implementation that wants these types.
Any ideas why the first request fails but subsequent work? I feel I need a fresh set of eyes as I'm running dry on ideas.
Last point, IIS 7.5 is the target both locally via IIS Express and on the destination server.
Thanks
EDIT for the bounty:
I'm copying my bounty message here and the Fiddler output for each request
I've added a few comments to this question. The issue appears related to NTLM. What I see in Fiddler is a 401 Unauthorized on request 1 with valid form data (point, it's my understanding that these first two 401 Unauthorized requests are "normal" under scenarios where only Windows Authentication is on; verify please?). Request 2 listed is again a 401 with the same form data except the uploaded file data is now just a bunch of boxes, the exact same size worth of data, just not the exact uploaded data. Request 3 is a 200 OK that contains the garbled data and this is what my controller action is getting. How do I get NTLM to play nice with file uploads?
Here's the Fiddler output for each request:
Request 1)
Request 2)
And finally request 3 that is the processed HTTP 200 OK
EDIT 2 After even further mucking about this appears to be a bug in Chrome 19. Please see here:
Nothing like an up to the minute bug! :-)
Firefox-latest and IE8/9 work as expected. The Fiddler logs show the same behavior with the major difference that the 2nd 401 authorization check does not send the form payload garbled and it works as expected.
It sounds like a test case and a fix is in the works! So, hopefully for any of you out there that may have run into this, this helps!
Thanks
This is just an idea to try. Note that StreamReader has many constructors:
http://msdn.microsoft.com/en-us/library/system.io.streamreader.aspx
In some of the constructors it attempts to autodetect the encoding (if specified) and if it cannot detect it then it falls back to the one specified. The constructor used uses UTF-8 encoding. You could change the constructor to autodetect the encoding and if not then use UTF-8.