如何在Razor中对CSV文件进行增删操作及代码复用?
实现Razor页面CSV数据删除及框架复用方案
一、实现删除操作
1. 后端处理逻辑
先定义产品-价格模型:
public class ProductPrice { public string ProductName { get; set; } public decimal Price { get; set; } }
在Razor页面的.cs文件中添加删除的POST处理方法:
public async Task<IActionResult> OnPostDeleteAsync(string productName) { // 定义CSV文件路径 var csvPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "products.csv"); // 读取所有行 var lines = await System.IO.File.ReadAllLinesAsync(csvPath); // 过滤掉目标行(跳过表头,匹配唯一标识字段) var updatedLines = lines.Where(line => !line.StartsWith($"{productName},") && !string.IsNullOrEmpty(line)).ToList(); // 写回更新后的内容 await System.IO.File.WriteAllLinesAsync(csvPath, updatedLines); // 重定向回页面刷新数据 return RedirectToPage(); }
2. 前端表格添加删除按钮
在.cshtml的表格循环中,为每行嵌入删除表单:
<table> <thead> <tr> <th>产品名称</th> <th>价格</th> <th>操作</th> </tr> </thead> <tbody> @foreach (var item in Model.ProductPrices) { <tr> <td>@item.ProductName</td> <td>@item.Price</td> <td> <form method="post"> <input type="hidden" name="productName" value="@item.ProductName" /> <button type="submit" asp-page-handler="Delete" class="btn btn-danger">删除</button> </form> </td> </tr> } </tbody> </table>
二、实现跨页面复用增删表格框架
1. 创建通用Razor组件
新建CsvCrudTable.cshtml组件,支持动态传入模型、字段配置和CSV路径:
@typeparam TItem @model CsvCrudTableModel<TItem> <!-- 动态新增表单 --> <form method="post" asp-page-handler="Add"> @foreach (var field in Model.FieldConfigs) { <div class="form-group"> <label>@field.DisplayName</label> <input type="@field.InputType" name="@field.FieldName" class="form-control" /> </div> } <button type="submit" class="btn btn-primary">新增</button> </form> <!-- 动态数据表格 --> <table> <thead> <tr> @foreach (var field in Model.FieldConfigs) { <th>@field.DisplayName</th> } <th>操作</th> </tr> </thead> <tbody> @foreach (var item in Model.Items) { <tr> @foreach (var field in Model.FieldConfigs) { <td>@item.GetType().GetProperty(field.FieldName)?.GetValue(item)</td> } <td> <form method="post"> <input type="hidden" name="@Model.DeleteKeyField" value="@item.GetType().GetProperty(Model.DeleteKeyField)?.GetValue(item)" /> <button type="submit" asp-page-handler="Delete" class="btn btn-danger">删除</button> </form> </td> </tr> } </tbody> </table>
配套的模型和字段配置类:
public class CsvCrudTableModel<TItem> { public List<TItem> Items { get; set; } public List<FieldConfig> FieldConfigs { get; set; } public string DeleteKeyField { get; set; } // 用于删除的唯一标识字段 public string CsvFilePath { get; set; } } public class FieldConfig { public string FieldName { get; set; } public string DisplayName { get; set; } public string InputType { get; set; } = "text"; }
2. 在具体页面中复用组件
以产品价格页面ProductPrices.cshtml为例:
@page @model ProductPricesModel @{ ViewData["Title"] = "产品价格管理"; } <CsvCrudTable TItem="ProductPrice" Model="@Model.CrudTableModel" />
对应的页面逻辑类ProductPricesModel.cs:
public class ProductPricesModel : PageModel { public CsvCrudTableModel<ProductPrice> CrudTableModel { get; set; } public async Task OnGetAsync() { var csvPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "products.csv"); CrudTableModel = new CsvCrudTableModel<ProductPrice> { Items = await ReadCsvAsync<ProductPrice>(csvPath), FieldConfigs = new List<FieldConfig> { new() { FieldName = "ProductName", DisplayName = "产品名称" }, new() { FieldName = "Price", DisplayName = "价格", InputType = "number" } }, DeleteKeyField = "ProductName", CsvFilePath = csvPath }; } // 新增操作 public async Task<IActionResult> OnPostAddAsync() { var newItem = MapFormToItem<ProductPrice>(Request.Form, CrudTableModel.FieldConfigs); await AppendToCsvAsync(CrudTableModel.CsvFilePath, newItem); return RedirectToPage(); } // 删除操作 public async Task<IActionResult> OnPostDeleteAsync(string productName) { var lines = await System.IO.File.ReadAllLinesAsync(CrudTableModel.CsvFilePath); var updatedLines = lines.Where(line => !line.StartsWith($"{productName},") && !string.IsNullOrEmpty(line)).ToList(); await System.IO.File.WriteAllLinesAsync(CrudTableModel.CsvFilePath, updatedLines); return RedirectToPage(); } // 通用CSV读取方法 private async Task<List<T>> ReadCsvAsync<T>(string path) where T : new() { var result = new List<T>(); var lines = await System.IO.File.ReadAllLinesAsync(path); var properties = typeof(T).GetProperties(); foreach (var line in lines.Skip(1)) { var values = line.Split(','); var item = new T(); for (int i = 0; i < properties.Length; i++) { properties[i].SetValue(item, Convert.ChangeType(values[i], properties[i].PropertyType)); } result.Add(item); } return result; } // 通用CSV追加方法 private async Task AppendToCsvAsync<T>(string path, T item) { var properties = typeof(T).GetProperties(); var values = properties.Select(p => p.GetValue(item).ToString()).ToArray(); await System.IO.File.AppendAllTextAsync(path, $"\n{string.Join(",", values)}"); } // 表单数据映射为模型 private T MapFormToItem<T>(IFormCollection form, List<FieldConfig> fieldConfigs) where T : new() { var item = new T(); foreach (var field in fieldConfigs) { var property = typeof(T).GetProperty(field.FieldName); property?.SetValue(item, Convert.ChangeType(form[field.FieldName], property.PropertyType)); } return item; } }
3. 其他页面复用示例
比如库存管理页面,只需替换模型、CSV路径和字段配置:
@page @model InventoryModel @{ ViewData["Title"] = "库存管理"; } <CsvCrudTable TItem="InventoryItem" Model="@Model.CrudTableModel" />
对应的InventoryItem模型和页面逻辑,复用通用的CSV操作方法即可。
内容的提问来源于stack exchange,提问作者Douar Gwenn
相关产品推荐
相关产品推荐

