Reading a HttpPostedFile before saving it saves a blank file in ASP.NET MVC
Before saving an uploaded csv file I want to check it will parse. When I was just saving the file everything was fine, now that I'm reading it first the file saved is blank.
Here is my action method
[HttpPost]
public ActionResult Import(HttpPostedFileBase file)
{
// Check parse went ok
using (var fileStream = file.InputStream)
{
if开发者_Python百科 (!MemberFileParsingService.CheckFileWillParse(fileStream))
{
ViewBag.Message = "There was a problem with the file";
return View();
}
}
// Save file so we can work on it in next action
file.SaveAs(Server.MapPath(fileName));
return RedirectToAction("ImportMatch", new { club = ActiveClub.Url });
}
And here's my method that checks to see if the file parses ok. It uses CsvReader to read through the whole file to check there are no errors. CsvReader throws exceptions when it comes to bad bits of the file.
public static bool CheckFileWillParse(Stream fileStream)
{
try
{
using (var reader = new StreamReader(fileStream))
{
using (CsvReader csv = new CsvReader(reader, false))
{
while (csv.ReadNextRecord()) { }
}
}
}
catch(Exception)
{
return false;
}
return true;
}
I think it's probably because it's trying to write the file using the same stream that is now at the end of the file. I don't know how to reset the stream though. I was hoping all my using statements would fix that problem.
So how can I reset the stream, or is that just a red herring?
Update: Found the length of the stream gets reset to zero after going through CheckFileWillParse so looks like resetting the stream is just a red herring and the stream is actually being blanked somehow.
You have to rewind the stream (if possible). Once you are doing reading it, the current position is at the end of the stream, that is why the file is empty when you save it.
You can use either the Seek function or the Position property to do this (set it to 0). Not all stream types support this though.
If a stream type doesn't support it, you may need to write the file out to disk first, then run your test against it.
Have you considered creating a copy of the stream to analyse, using Stream.CopyTo()
?
Because of the using
statement, the Dispose()
method on your StreamReader
object will be called. This will actually close the underlying Stream
object. Hence why the stream is of zero length.
Option 1:
One option is to not dispose of the StreamReader
instance by removing the using
statement. You will need to manually dispose of the stream later (but maybe CsvReader
will do this for you) by calling its Dispose()
method.
The garbage collector will clean up the StreamReader
object and will not close the underlying stream.
Option 2:
You can use the following constructor when instantiating StreamReader
:
public StreamWriter(
Stream stream,
Encoding encoding,
int bufferSize,
bool leaveOpen
)
Setting the leaveOpen
parameter to true
will ensure that the stream will not be closed.
Since the StreamReader Dispose Method will dispose your underlying Stream as well.
MemoryStream ms = new MemoryStream();
myStream.CopyTo(ms);
myStream.Position = ms.Position = 0; // !Don't forget this!
//And then read your 'ms' here
精彩评论