Let's say that you built an ASP.NET Core application that displays reports using the ActiveReports JavaScript Viewer. Some reports use various parameters, and at some point, you need to collect the analytics of reporting usage, such as how often a report is requested, which parameters are passed to a report, how long it takes to render a report, etc. This task consists of 2 sub-tasks:
This article shows how to implement the first sub-task with ASP.NET Core middleware that intercepts requests from the ActiveReports JS Viewer to the ASP.NET Core back-end.
Let's go through the process step by step using a basic parametrized report.
Add the following code at the beginning of the Startup class. We will use this regular expression to extract the Report Name.
private static Regex RenderRequestRegex = new Regex("/api/reporting/reports/(.+)/render");
Add the following class declaration after the Startup class. We will use this class to extract report parameters values from the request.
class RenderRequest
{
public Dictionary<string, object[]> Parameters { get; set; }
}
Modify the Configure method of the Startup class as follows. First, the application invokes the new middleware branch when the JS viewer sends the render request described above. Then, the code extracts the report name and parameters' values from the request's path and body, respectively. Note that for the sake of simplicity, this information is sent to the logger output using the "warning" level. The actual application could save the information in a database.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseWhen(context => RenderRequestRegex.IsMatch(context.Request.Path.Value), (app) =>
{
app.Use(async (context, next) =>
{
// extract the report name from the request
var reportName = RenderRequestRegex.Match(context.Request.Path.Value).Groups[1].Value;
logger.LogWarning($"Report {reportName} has been requested at {DateTime.Now:dd-MM-yyyy HH:mm:ss}");
context.Request.EnableBuffering();
using (var reader = new StreamReader(context.Request.Body, encoding: Encoding.UTF8, detectEncodingFromByteOrderMarks: false, bufferSize: 1024, leaveOpen: true))
{
var body = await reader.ReadToEndAsync();
// extract parameters values from the body request
var renderRequest = Newtonsoft.Json.JsonConvert.DeserializeObject<RenderRequest>(body);
foreach (var kv in renderRequest.Parameters)
{
logger.LogWarning($"Parameter {kv.Key} has values {string.Join(",", kv.Value)}");
}
context.Request.Body.Position = 0;
}
await next.Invoke();
});
});
app.UseReporting(settings =>
{
settings.UseEmbeddedTemplates(EmbeddedReportsPrefix, Assembly.GetAssembly(GetType()));
settings.UseCompression = true;
});
app.UseMvc();
}
Rerun the application, specify the parameter value, and ensure that the report renders as expected. Now the logger output contains the additional information, here is the corresponding excerpt highlighted: