Blazor中的CSVHelper泛型组件-如何传递类型映射



我们正在使用。net 7下的服务器端Blazor创建一个LOB应用程序/站点。在每个列表上,我们都有一个下载CSV文件的按钮。对于一次性的东西来说,工作得很好,但它有很多重复的代码,并且必须在任何地方进行更改。输入……(ta-da…)通用组件!

我把所有需要的东西都包装到一个组件中,我的下载按钮就像预期的那样工作了。我们下载的每个东西都定义了一个POCO/EF类。我可以把这个类作为TypeParm (<T>)传递给我的组件。

我的问题是大多数这些类都有一个匹配的Map类。有些事情我不完全理解(泛型不是我的强项),但是Blazor组件在处理多个泛型类型时遇到了麻烦。

如果有可能传递一个<T>和一个,比如<U>,我不知道怎么做。有一些关于部分类和泛型的文章,并且在早期的Blazor/razor版本中可能存在一些错误。

我可以将类型类映射的NAME作为字符串传递,但我不知道如何传递类或如何将TypeName的字符串变为类本身以调用RegisterClassMap

如果有人能分享这个神奇的酱汁,或者告诉我去哪里获取更多的信息,我将非常感激。

在评论这些建议(在发布之前)时,我没有看到类似的东西,但我想知道这种方法是否会有一个超类:

public class TypeForCSV 
{
object TheListClass,
object TheMapClass
}

但我(个人)仍然会纠结于如何定义它以使其通用。

谢谢大家。

这是我的组件。评论栏是我的问题。(是的,我们也使用MudBlazor)


@using BlazorDownloadFile
@typeparam T

<MudButton Variant="@(_processing ?  Variant.Filled : Variant.Outlined )"
           DisableElevation="true"
           Size="Size.Small"
           Color="Color.Primary"
           StartIcon="@(_processing ? "" : Icons.Filled.BrowserUpdated)"
           OnClick="@ExportToCSV"
           Disabled="@_processing"
           Class="ma-2 mt-8">

    @if (_processing)
    {
        <MudProgressCircular Class="ms-n1" Size="Size.Small" Indeterminate="true" />
        <span> Preparing...</span>
    }
    else
    {
        <span>Export CSV</span>
    }
</MudButton>

@code {

    private bool _processing = false;

    [Inject] public IBlazorDownloadFileService? BlazorDownloadFileService { get; set; }
    [Parameter] public string FileNameBase { get; set; } = "";
    [Parameter] public string CsvMapType { get; set; } = "NothingToSeeHere";
    [Parameter] public Func<Task<List<T>>>? OnListRequest { get; set; }

    public List<T> ListItems { get; set; } = new();
    private string _csv = "";

    private string MakeCsvString(List<T> items)
    {
        using (var writer = new StringWriter())
        using (var csv1 = new CsvWriter(writer, CultureInfo.InvariantCulture))
        {
            // csv1.Context.RegisterClassMap<U>();    // use a different overload?
            csv1.WriteRecords(items);
            return writer.ToString();
        }
    }

    private async Task ExportToCSV()
    {
        _processing = true;
        StateHasChanged();
        ListItems = await OnListRequest();
        _csv = MakeCsvString(ListItems);
        string filename = $"{FileNameBase.IfNullOrWhiteSpace("Download")}-{DateTime.Now:yyyyMMdd-HHmm}.csv";
        await BlazorDownloadFileService.DownloadFileFromText(filename, _csv, System.Text.Encoding.UTF8, "text/csv");
        await Task.Yield();
        _processing = false;
        StateHasChanged();
    }

}

根据Craig Brown对的回答,泛型类型约束在blazor中可能吗?,从开始。网6您可以在Blazor中使用通用约束。由于使用的是。net 7,您可以定义第二个泛型参数,并将其约束为ClassMap<T>,如下所示:

@typeparam TMap where TMap : CsvHelper.Configuration.ClassMap<T>
所以你的完整代码可能看起来像:
@using BlazorDownloadFile
@typeparam T
@typeparam TMap where TMap : CsvHelper.Configuration.ClassMap<T>

<MudButton Variant="@(_processing ?  Variant.Filled : Variant.Outlined )"
DisableElevation="true"
Size="Size.Small"
Color="Color.Primary"
StartIcon="@(_processing ? "" : Icons.Filled.BrowserUpdated)"
OnClick="@ExportToCSV"
Disabled="@_processing"
Class="ma-2 mt-8">

@if (_processing)
{
<MudProgressCircular Class="ms-n1" Size="Size.Small" Indeterminate="true" />
<span> Preparing...</span>
}
else
{
<span>Export CSV</span>
}
</MudButton>

@code {

private bool _processing = false;

[Inject] public IBlazorDownloadFileService? BlazorDownloadFileService { get; set; }
[Parameter] public string FileNameBase { get; set; } = "";
[Parameter] public Func<Task<List<T>>>? OnListRequest { get; set; }

public List<T> ListItems { get; set; } = new();
private string _csv = "";

private string MakeCsvString(List<T> items)
{
using (var writer = new StringWriter())
using (var csv1 = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv1.Context.RegisterClassMap<TMap>();
csv1.WriteRecords(items);
return writer.ToString();
}
}

private async Task ExportToCSV()
{
_processing = true;
StateHasChanged();
ListItems = await OnListRequest();
_csv = MakeCsvString(ListItems);
string filename = $"{FileNameBase.IfNullOrWhiteSpace("Download")}-{DateTime.Now:yyyyMMdd-HHmm}.csv";
await BlazorDownloadFileService.DownloadFileFromText(filename, _csv, System.Text.Encoding.UTF8, "text/csv");
await Task.Yield();
_processing = false;
StateHasChanged();
} 
}

您可以传入任意多的泛型类型,每个类型都有限制。

组件:

@typeparam TRecord where TRecord: class, new()
@typeparam TService where TService: class, IService<TRecord>
@typeparam TBase where TBase: class, IDisposable
<h3>Component</h3>
@code {
}

:

@page "/"
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<Component TBase=TestBaseClass TRecord=TestTRecord TService=TestService />
@code {
}

我建议使用接口来限定可以传递的类,并为泛型类型使用描述性名称,而不是TU,以使代码更具可读性。

最新更新