New to Telerik Reporting? Download free 30-day trial

How to render reports asynchronously by using the async and await keywords

Environment

Product Progress® Telerik® Reporting
Framework .NET Framework 4.5 and higher

Description

With the new .NET Framework (4.5), a new way to handle parallel programming has been added - with the help of the Task<> class and the keywords async and await, parallel programming has become much easier. This raises the question, how can these features be used with Telerik Reporting?

Solution

First, we will have to start with the ReportProcessor class and its RenderReport method, which provides all the needed functionality for programmatic generation of reports. Since RenderReport returns RenderingResult, in order to use it asynchronously, you will have to create a method that returns this result. However, since we want to achieve the task in an async manner, we will take advantage of the Task class:

public class AsyncWrappers
{
    // Wrap the RenderingResult like this:
    public async Task<RenderingResult> RenderReportAsync(Type reportType) // Pass parameters here, like device info and report to render
    {
        ReportProcessor reportProcessor = new ReportProcessor();

        // Apply any deviceInfo settings if necessary
        Hashtable deviceInfo = new Hashtable();

        // Any other Report Source can be used instead
        // For example InstanceReportSource can be used if the instantiated report is passed as parameter of the method
        TypeReportSource typeReportSource = new TypeReportSource();

        typeReportSource.TypeName = reportType.AssemblyQualifiedName;

        return await Task.Run(() => reportProcessor.RenderReport("PDF", typeReportSource, deviceInfo));
    }
}

Besides declaring the return value to be Task<RenderingResult> we have marked the method as async. Also, we are invoking the RenderReport method using the await keyword. For the second part, we will use our method in an async manner:

//Use the wrapper in your code like this:
public async Task<string> RenderReportAsync()
{
    var asyncWrappers = new AsyncWrappers();

    Console.WriteLine("Rendering started on: {0}", Thread.CurrentThread.ManagedThreadId);

    var result = await asyncWrappers.RenderReportAsync( typeof(Telerik.Reporting.Report) );// pass the type of your report here

    string fileName = result.DocumentName + "." + result.Extension;
    string path = System.IO.Path.GetTempPath();
    string filePath = System.IO.Path.Combine(path, fileName);

    using (System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Create))
    {
        fs.Write(result.DocumentBytes, 0, result.DocumentBytes.Length);
    }

    Console.WriteLine("Rendering finished on: {0}\n", Thread.CurrentThread.ManagedThreadId);

    // You can return void but that is not recommended
    return string.Format("Successfully rendered! File saved in {0}\n", filePath);
}

Finally, we will invoke this method in a console application and check the results:

class Program
{
    // A working example
    static void Main(string[] args)
    {
        // Use your class to render the report in an async manner
        var myClass = new MyClass();

        Console.WriteLine("Starting rendering...");
        var task = myClass.RenderReportAsync();

        // While the report is rendering do something else
        Count();

        Console.WriteLine("Main finished on: {0}", Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine("Render Status: {0}\n", task.Result);

        Console.ReadLine();
    }

    static void Count()
    {
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine(i);
        }
    }
}

Additional Resources

Download a sample console application.

See Also

Embedded Report Engine