You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 21:17:02