.NET MVC Core学生数据验证及文件上传导出实现方案咨询
.NET MVC Core 学生数据验证与文件导出实现方案
核心实现流程
- 定义学生数据模型及验证规则
- 实现CSV文件解析与数据校验逻辑
- 生成有效/错误数据文件并提供下载
- 构建前端上传与结果展示界面
1. 模型定义(含验证规则)
使用数据注解实现基础字段校验,同时定义验证结果模型存储校验状态:
public class Student { [Required(ErrorMessage = "学号不能为空")] [StringLength(20, ErrorMessage = "学号长度不能超过20位")] public string StudentId { get; set; } [Required(ErrorMessage = "姓名不能为空")] [StringLength(50, ErrorMessage = "姓名长度不能超过50位")] public string Name { get; set; } [Range(15, 30, ErrorMessage = "年龄必须在15-30之间")] public int Age { get; set; } [EmailAddress(ErrorMessage = "邮箱格式不正确")] public string Email { get; set; } } public class StudentValidationResult { public Student ValidStudent { get; set; } public string ErrorMessage { get; set; } public bool IsValid => string.IsNullOrEmpty(ErrorMessage); }
2. 数据处理服务
实现文件解析、校验、导出逻辑,依赖CsvHelper处理CSV文件(需安装NuGet包:Install-Package CsvHelper):
public interface IStudentDataService { List<StudentValidationResult> ParseAndValidateFile(IFormFile file); byte[] GenerateValidStudentsCsv(List<StudentValidationResult> results); byte[] GenerateErrorStudentsCsv(List<StudentValidationResult> results); } public class StudentDataService : IStudentDataService { public List<StudentValidationResult> ParseAndValidateFile(IFormFile file) { var results = new List<StudentValidationResult>(); using var reader = new StreamReader(file.OpenReadStream()); using var csv = new CsvReader(reader, CultureInfo.InvariantCulture); var records = csv.GetRecords<Student>(); foreach (var student in records) { var validationContext = new ValidationContext(student); var validationErrors = new List<ValidationResult>(); var isValid = Validator.TryValidateObject(student, validationContext, validationErrors, validateAllProperties: true); results.Add(new StudentValidationResult { ValidStudent = student, ErrorMessage = isValid ? null : string.Join("; ", validationErrors.Select(e => e.ErrorMessage)) }); } return results; } public byte[] GenerateValidStudentsCsv(List<StudentValidationResult> results) { var validStudents = results.Where(r => r.IsValid).Select(r => r.ValidStudent).ToList(); using var memoryStream = new MemoryStream(); using var writer = new StreamWriter(memoryStream); using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture); csv.WriteRecords(validStudents); writer.Flush(); return memoryStream.ToArray(); } public byte[] GenerateErrorStudentsCsv(List<StudentValidationResult> results) { var errorRecords = results.Where(r => !r.IsValid) .Select(r => new { r.ValidStudent.StudentId, r.ValidStudent.Name, r.ValidStudent.Age, r.ValidStudent.Email, r.ErrorMessage }) .ToList(); using var memoryStream = new MemoryStream(); using var writer = new StreamWriter(memoryStream); using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture); csv.WriteRecords(errorRecords); writer.Flush(); return memoryStream.ToArray(); } }
3. 控制器实现
处理文件上传、校验结果展示及文件下载请求:
public class StudentController : Controller { private readonly IStudentDataService _studentDataService; public StudentController(IStudentDataService studentDataService) { _studentDataService = studentDataService; } public IActionResult Index() => View(); [HttpPost] public IActionResult Upload(IFormFile file) { if (file == null || file.Length == 0) { ModelState.AddModelError("file", "请选择要上传的文件"); return View("Index"); } if (!file.FileName.EndsWith(".csv", StringComparison.OrdinalIgnoreCase)) { ModelState.AddModelError("file", "仅支持CSV格式文件"); return View("Index"); } var validationResults = _studentDataService.ParseAndValidateFile(file); TempData["ValidCount"] = validationResults.Count(r => r.IsValid); TempData["ErrorCount"] = validationResults.Count(r => !r.IsValid); TempData["ValidationResults"] = validationResults; return RedirectToAction("Result"); } public IActionResult Result() { if (TempData["ValidationResults"] == null) return RedirectToAction("Index"); ViewBag.ValidCount = TempData["ValidCount"]; ViewBag.ErrorCount = TempData["ErrorCount"]; return View(); } public IActionResult DownloadValidData() { var results = TempData.Peek("ValidationResults") as List<StudentValidationResult>; if (results == null) return NotFound(); var csvBytes = _studentDataService.GenerateValidStudentsCsv(results); return File(csvBytes, "text/csv", $"有效学生数据_{DateTime.Now:yyyyMMddHHmmss}.csv"); } public IActionResult DownloadErrorData() { var results = TempData.Peek("ValidationResults") as List<StudentValidationResult>; if (results == null) return NotFound(); var csvBytes = _studentDataService.GenerateErrorStudentsCsv(results); return File(csvBytes, "text/csv", $"错误学生数据_{DateTime.Now:yyyyMMddHHmmss}.csv"); } }
4. 前端UI实现
上传页面(Index.cshtml)
@{ ViewData["Title"] = "学生数据上传验证"; } <h1>学生数据上传验证</h1> <form method="post" enctype="multipart/form-data"> <div class="mb-3"> <label for="file" class="form-label">选择CSV文件</label> <input type="file" class="form-control" id="file" name="file" accept=".csv"> @if (!ModelState.IsValid) { <span class="text-danger">@ModelState["file"].Errors.First().ErrorMessage</span> } </div> <button type="submit" class="btn btn-primary">上传并验证</button> </form>
结果页面(Result.cshtml)
@{ ViewData["Title"] = "验证结果"; } <h1>验证结果</h1> <div class="alert alert-info"> 有效数据: @ViewBag.ValidCount 条 | 错误数据: @ViewBag.ErrorCount 条 </div> @if (ViewBag.ValidCount > 0) { <a href="@Url.Action("DownloadValidData")" class="btn btn-success me-2">下载有效数据</a> } @if (ViewBag.ErrorCount > 0) { <a href="@Url.Action("DownloadErrorData")" class="btn btn-danger">下载错误数据</a> } <p><a href="@Url.Action("Index")" class="btn btn-secondary">返回上传页面</a></p>
5. 服务注册
在Program.cs中注册数据处理服务:
builder.Services.AddScoped<IStudentDataService, StudentDataService>(); builder.Services.AddControllersWithViews();
关键注意事项
- CSV文件表头需与
Student模型属性名完全匹配(如StudentId,Name,Age,Email) - 如需支持Excel文件,可替换
CsvHelper为EPPlus库实现 - 大文件场景建议采用流式处理避免内存溢出
- 可扩展添加自定义校验规则(如学号唯一性检查,需结合数据库查询)
内容的提问来源于stack exchange,提问作者Radha Kadam
相关产品推荐
相关产品推荐

