0%

DevExpress Reporting - ASP.NET Core项目中实现参数校验

背景

DevExpress Reporting是DevExpress产品系列下的一个重要的模块,能在WinForms,WPS,ASP.NET,Blazor等众多平台下帮助用户快速创建美观的报告、报表。在构建通用程度高的报表时,往往需要接收参数以生成对应条件下的报表。本片博文将分享在ASP.NET Core中如何实现定制化的报表参数校验机制。

思路

DevExpress Reporting的SDK提供了一个叫WebDocumentViewerOperationLogger的类,根据名字也可推断这个类是作为Viewer生成过程中的日志方法的基类。通过简单的反编译可以发现这个类包含了众多标记为virtual方法,基本涵盖了从报表打开到报表实例销毁的整个生命周期,而这个基类本身对各个方法基本是空实现,所以从设计上看这个类就是专门为用户自定义扩展而存在的。

编码

  1. 创建继承WebDocumentViewerOperationLogger的子类CustomWebDocumentViewerOperationLogger
1
2
3
4
5
6
7
8
9
10
11
12
13
public class CustomWebDocumentViewerOperationLogger : WebDocumentViewerOperationLogger
{
private readonly IReportInterceptorService _reportInterceptorService;

...

public override async Task<Action> BuildStartingAsync(string reportId, string reportUrl, XtraReport report, ReportBuildProperties buildProperties)
{
await _reportInterceptorService.PreBuildStartAsync(report.Name, buildProperties.Parameters);
return null;
}
...
}

在这里博主只演示重写BuildStartingAsync的方法,读者可自行选择生命周期事件进行重写。博主使用了一个另外一个服务类来提供具体的事件处理业务。需要注意的是方法签名中的4个参数,其中report参数提供了当前报表文档示例的所有属性,而buildProperties参数中提供了用户输入的报表参数。

  1. 在具体业务逻辑类中进行参数校验:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class DonationTaxSummaryReportInterceptor : IReportInterceptorService
{
public override Task PreBuildStartAsync(string reportName, Dictionary<string, object> parameters)
{
var dateRange = GetDateRange(parameters);
if (!dateRange.HasValue)
{
throw new ArgumentException("Please select a year range.");
}

return Task.CompletedTask;
}

private (DateTime, DateTime)? GetDateRange(Dictionary<string, object> parameters)
{
var years = parameters["Years"] as string;
if (string.IsNullOrWhiteSpace(years) || year.Length != 8)
{
return null;
}

if (int.TryParse(years[..4], out var yearFrom) && int.TryParse(years[^4..], out var yearTo))
{
var dateFrom = new DateTime(yearFrom, 4, 1);
var dateTo = new DateTime(yearTo, 3, 31);

return (dateFrom, dateTo);
}

return null;
}
}

这里以校验一个必需的年份范围参数为例,若校验失败,则直接抛出异常,因为这个类并不应具有处理异常的能力。

  1. 参数校验完毕后,如果有失败的结果以异常的形式向上抛出,我们可以在上层捕获,处理为用户友好文字后,最终以DocumentCreationException的形式抛出。DocumentCreationException类是DevExpress的SDK中定义的异常类,在文档实例生命周期中抛出的该类型的类会被DevExpress处理为前端页面可识别的异常,最终显示在用户界面上。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void HandleDocumentBuildException(Exception e)
{
string message;
if (e is AggregateException aggregateException)
{
message = aggregateException.InnerExceptions.First().Message;
}
else
{
message = e.Message;
}

throw new DocumentCreationException(string.IsNullOrEmpty(message) ? "Internal Server Error" : message);
}