InputStream, return 开始
InputStream, return to beginning
我有一个控制器post方法,需要上传文件:
查看:
@using (Html.BeginForm("UploadCSV", "TemporaryPerson", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
@Html.ValidationSummary(false, "", new { @class = "text-danger" })
<br />
<input type="file" name="personFile" /><input type="submit" value="Upload" />
</div>
}
和控制器方法:
[HttpPost]
public ActionResult UploadCSV(UploadCsvViewModel model)
{
if (ModelState.IsValid)
{
using (StreamReader reader = new StreamReader(Request.Files[0].InputStream))
{
using (var csv = new CsvReader(reader))
{
var records = csv.GetRecords<TemporaryPersonCsv>().ToList();
foreach (var record in records)
{
//...................
}
}
}
}
return View();
}
它工作正常。但我想将所有验证移至 UploadCsvViewModel:
public class UploadCsvViewModel : IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var results = new List<ValidationResult>();
if (HttpContext.Current.Request.Files == null || HttpContext.Current.Request.Files.Count == 0 || HttpContext.Current.Request.Files[0].ContentLength == 0)
results.Add(new ValidationResult("File is not selected or empty", new string[] { "NoFile" }));
using (StreamReader reader = new StreamReader(HttpContext.Current.Request.Files[0].InputStream))
{
using (var csv = new CsvReader(reader))
{
var enumeraterecords = csv.GetRecords<TemporaryPersonCsv>();
if (enumeraterecords != null)
{
var records = enumeraterecords.ToList();
if (records == null || records.Count == 0)
results.Add(new ValidationResult("No records in file", new string[] { "NoRecords" }));
// different validation, according with business logic
}
else
results.Add(new ValidationResult("No records in file", new string[] { "NoRecords" }));
}
}
return results;
}
}
问题是如果我在 UploadCsvViewModel 中有 Validate 方法,然后我得到错误:
Exception Details: CsvHelper.CsvReaderException: No header record was
found.
在线:
var records = csv.GetRecords<TemporaryPersonCsv>().ToList();
在控制器方法中。我假设 InputStream 的位置无效。我试过了:
复制到另一个流:
using (MemoryStream ms = new MemoryStream())
{
HttpContext.Current.Request.Files[0].InputStream.CopyTo(ms, HttpContext.Current.Request.Files[0].ContentLength);
没有帮助
在验证方法结束时将输入流位置设置为 0:
HttpContext.Current.Request.Files[0].InputStream.Position = 0;
没有帮助
为 'reader' 对象调用 DiscardBufferedData
reader.DiscardBufferedData();
也没有帮助。
我找到了解决方案。我将 InputStream 复制到另一个流(即 MemoryStream),然后我可以为两个流(InputStream 和 MemoryStream)设置 Position=0 并且它有效。
验证方法:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var results = new List<ValidationResult>();
if (HttpContext.Current.Request.Files == null || HttpContext.Current.Request.Files.Count == 0 || HttpContext.Current.Request.Files[0].ContentLength == 0)
results.Add(new ValidationResult("File is not selected or empty", new string[] { "NoFile" }));
using (MemoryStream ms = new MemoryStream())
{
HttpContext.Current.Request.Files[0].InputStream.CopyTo(ms);
ms.Position = 0;
using (StreamReader reader = new StreamReader(ms))
{
using (var csv = new CsvReader(reader))
{
var enumeraterecords = csv.GetRecords<TemporaryPersonCsv>();
if (enumeraterecords != null)
{
var records = enumeraterecords.ToList();
if (records == null || records.Count == 0)
results.Add(new ValidationResult("No records in file", new string[] { "NoRecords" }));
// find dublicates in CSV file
var dublicates = (records.GroupBy(p => p.Fullname.ToLower().Trim()).Where(p => p.Count() > 1).Select(p => p.Key)).ToList();
if (dublicates != null && dublicates.Count > 0)
{
foreach (var dublicateFullname in dublicates)
{
results.Add(new ValidationResult(String.Concat("There are 2 or more records with fullname='", dublicateFullname, "' in your csv file. Please, fix your file and upload again."), new string[] { "DublicateRecords" }));
}
}
// find dublicates in TemporaryPersons and Persons tables
PlugandabandonEntities db = new PlugandabandonEntities();
foreach (var record in records)
{
if (db.TemporaryPerson.Where(p => p.Fullname.ToLower() == record.Fullname.ToLower()).Count() > 0)
results.Add(new ValidationResult(String.Concat("Record with fullname='", record.Fullname, "' already exists in TemporaryPersons. Please, fix your file and upload again."), new string[] { "RecordExistsInTemporaryPerson" }));
if (db.Person.Where(p => p.Fullname.ToLower() == record.Fullname.ToLower()).Count() > 0)
results.Add(new ValidationResult(String.Concat("Record with fullname='", record.Fullname, "' already exists in Persons. Please, fix your file and upload again."), new string[] { "RecordExistsInPersons" }));
}
}
else
results.Add(new ValidationResult("No records in file", new string[] { "NoRecords" }));
}
reader.DiscardBufferedData();
}
}
HttpContext.Current.Request.Files[0].InputStream.Position = 0;
return results;
}
然后我们在控制器方法中有一个 "virgin" InputStream,我们可以根据需要使用它;)
我有一个控制器post方法,需要上传文件:
查看:
@using (Html.BeginForm("UploadCSV", "TemporaryPerson", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
@Html.ValidationSummary(false, "", new { @class = "text-danger" })
<br />
<input type="file" name="personFile" /><input type="submit" value="Upload" />
</div>
}
和控制器方法:
[HttpPost]
public ActionResult UploadCSV(UploadCsvViewModel model)
{
if (ModelState.IsValid)
{
using (StreamReader reader = new StreamReader(Request.Files[0].InputStream))
{
using (var csv = new CsvReader(reader))
{
var records = csv.GetRecords<TemporaryPersonCsv>().ToList();
foreach (var record in records)
{
//...................
}
}
}
}
return View();
}
它工作正常。但我想将所有验证移至 UploadCsvViewModel:
public class UploadCsvViewModel : IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var results = new List<ValidationResult>();
if (HttpContext.Current.Request.Files == null || HttpContext.Current.Request.Files.Count == 0 || HttpContext.Current.Request.Files[0].ContentLength == 0)
results.Add(new ValidationResult("File is not selected or empty", new string[] { "NoFile" }));
using (StreamReader reader = new StreamReader(HttpContext.Current.Request.Files[0].InputStream))
{
using (var csv = new CsvReader(reader))
{
var enumeraterecords = csv.GetRecords<TemporaryPersonCsv>();
if (enumeraterecords != null)
{
var records = enumeraterecords.ToList();
if (records == null || records.Count == 0)
results.Add(new ValidationResult("No records in file", new string[] { "NoRecords" }));
// different validation, according with business logic
}
else
results.Add(new ValidationResult("No records in file", new string[] { "NoRecords" }));
}
}
return results;
}
}
问题是如果我在 UploadCsvViewModel 中有 Validate 方法,然后我得到错误:
Exception Details: CsvHelper.CsvReaderException: No header record was found.
在线:
var records = csv.GetRecords<TemporaryPersonCsv>().ToList();
在控制器方法中。我假设 InputStream 的位置无效。我试过了:
复制到另一个流:
using (MemoryStream ms = new MemoryStream()) { HttpContext.Current.Request.Files[0].InputStream.CopyTo(ms, HttpContext.Current.Request.Files[0].ContentLength);
没有帮助
在验证方法结束时将输入流位置设置为 0:
HttpContext.Current.Request.Files[0].InputStream.Position = 0;
没有帮助
为 'reader' 对象调用 DiscardBufferedData
reader.DiscardBufferedData();
也没有帮助。
我找到了解决方案。我将 InputStream 复制到另一个流(即 MemoryStream),然后我可以为两个流(InputStream 和 MemoryStream)设置 Position=0 并且它有效。
验证方法:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var results = new List<ValidationResult>();
if (HttpContext.Current.Request.Files == null || HttpContext.Current.Request.Files.Count == 0 || HttpContext.Current.Request.Files[0].ContentLength == 0)
results.Add(new ValidationResult("File is not selected or empty", new string[] { "NoFile" }));
using (MemoryStream ms = new MemoryStream())
{
HttpContext.Current.Request.Files[0].InputStream.CopyTo(ms);
ms.Position = 0;
using (StreamReader reader = new StreamReader(ms))
{
using (var csv = new CsvReader(reader))
{
var enumeraterecords = csv.GetRecords<TemporaryPersonCsv>();
if (enumeraterecords != null)
{
var records = enumeraterecords.ToList();
if (records == null || records.Count == 0)
results.Add(new ValidationResult("No records in file", new string[] { "NoRecords" }));
// find dublicates in CSV file
var dublicates = (records.GroupBy(p => p.Fullname.ToLower().Trim()).Where(p => p.Count() > 1).Select(p => p.Key)).ToList();
if (dublicates != null && dublicates.Count > 0)
{
foreach (var dublicateFullname in dublicates)
{
results.Add(new ValidationResult(String.Concat("There are 2 or more records with fullname='", dublicateFullname, "' in your csv file. Please, fix your file and upload again."), new string[] { "DublicateRecords" }));
}
}
// find dublicates in TemporaryPersons and Persons tables
PlugandabandonEntities db = new PlugandabandonEntities();
foreach (var record in records)
{
if (db.TemporaryPerson.Where(p => p.Fullname.ToLower() == record.Fullname.ToLower()).Count() > 0)
results.Add(new ValidationResult(String.Concat("Record with fullname='", record.Fullname, "' already exists in TemporaryPersons. Please, fix your file and upload again."), new string[] { "RecordExistsInTemporaryPerson" }));
if (db.Person.Where(p => p.Fullname.ToLower() == record.Fullname.ToLower()).Count() > 0)
results.Add(new ValidationResult(String.Concat("Record with fullname='", record.Fullname, "' already exists in Persons. Please, fix your file and upload again."), new string[] { "RecordExistsInPersons" }));
}
}
else
results.Add(new ValidationResult("No records in file", new string[] { "NoRecords" }));
}
reader.DiscardBufferedData();
}
}
HttpContext.Current.Request.Files[0].InputStream.Position = 0;
return results;
}
然后我们在控制器方法中有一个 "virgin" InputStream,我们可以根据需要使用它;)