InputStream,返回开头

时间:2015-05-03 20:08:18

标签: c# validation stream asp.net-mvc-5 inputstream

我有一个控制器发布方法,需要上传文件:

查看:

@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方法,那么我得到错误:

  

异常详细信息:CsvHelper.CsvReaderException:没有标头记录   找到。

在线:

var records = csv.GetRecords<TemporaryPersonCsv>().ToList();

在控制器方法中。我假设,InputStream的位置无效。我试过了:

  1. 复制到另一个流:

    using (MemoryStream ms = new MemoryStream())
    {
        HttpContext.Current.Request.Files[0].InputStream.CopyTo(ms, HttpContext.Current.Request.Files[0].ContentLength);
    
  2. 没有帮助

    1. 在验证方法结束时将输入流位置设置为0:

      HttpContext.Current.Request.Files [0] .InputStream.Position = 0;

    2. 没有帮助

      1. 为'reader'对象调用DiscardBufferedData

                reader.DiscardBufferedData();
        
      2. 也没有帮助。

1 个答案:

答案 0 :(得分:0)

我找到了解决方案。我将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;
    }

然后我们在控制器方法中有一个“处女”的InputStream,我们可以随意使用它;)