In this article, I’ll explain how to create reports using Aspose.Words, a powerful tool for presenting complex data in a variety of ways. Why do I love using it? First, because it’s easy to maintain (one Word document per report). And second, because it generates documents at warp speed—a matter of seconds in the architecture proposed here. So far, I’ve used it for a web project, but here I’ll explain a simple way to use it within the Dataverse or Dynamics 365.
Unfortunately, we can’t integrate the Aspose library directly. Why not? Because we can’t merge two libraries together (for example, plug-in library and the libraries needed for Aspose). It would work, but it’s not supported by Microsoft. So, what’s the solution?
If you look at the figure of the basic architecture above, you’ll see that we can create an Azure function into which we feed the data, which will generate as a report.
Aspose.Words: A simple example
Want concrete examples? Using sample data, I thought I would show you what I can do in my own environment. First, I click on the Get pdf button to save the PDF to the disk.
In the example above, I used a Word document containing a table. For each of the accounts, the contacts are presented as book titles.
|<<foreach [a in entities]>><<[ _primarycontactid_valueODataCommunityDisplayV1FormattedValue]>>||<<[a.name]>><</foreach>>|
It gives the following output:
|Yvonne McKay (example)||Fourth Coffee (example)|
|Susanna Stubberod (example)||Litware Inc. (example)|
|Nancy Anderson (example)||Adventure Works (example)|
|Maria Campbell (example)||Fabrikam Inc. (example)|
|Sidney Higa (example)||Blue Yonder Airlines (example)|
|Scott Konersmann (example)||City Power & Light (example)|
|Robert Lyon (example)||Contoso Pharmaceuticals (example)|
|Paul Cannon (example)||Alpine Ski House (example)|
|Rene Valdes (example)||A. Datum Corporation (example)|
|Jim Glynn (example)||Coho Winery (example)|
Aspose.Words: A complex example
Now, let’s get a little more complicated… In our in-house software TANDEM, designed for insurance agents, the most complex reports take around 20 minutes to generate. To generate the reports, we use XPertDoc, which is very powerful when it comes to transforming data; however, the license is very expensive. It’s also hard to maintain and difficult to develop, which is why we’re looking at alternative solutions.
So, after two days of work and a quick re-design in Aspose.Words… here we are! It now takes no more than 20 seconds for the new report to generate (first cold call to the Azure function), and after that, literally 2 seconds.
Here’s the Word template:
|<<foreach [ k in ListQuoteBenefits.Keys]>><<[k]>>||<<[ name.ListQuoteBenefits [k]?.QuoteDetails?. xrm_volume] :”0.##”>>||<<[ name.ListQuoteBenefits [k]?.QuoteDetails?. PricePerUnit] :”0.##”>>||<<[ name.ListQuoteBenefits [k]?.QuoteDetails?. BaseAmount] :”0.##”>>||<<[ name.ListQuoteBenefits [k]?.QuoteDetails?. PricePerUnit] :”0.##”>>||<<[ name.ListQuoteBenefits [k]?.QuoteDetails?. BaseAmount] :”0.##”>>||<<if [ name.ListQuoteBenefits [k]?.QuoteDetails?. BaseAmount != null && name.ListQuoteBenefits [k]?.QuoteDetails?. BaseAmount != 0]>><<[name.ListQuoteBenefits [k]?.QuoteDetails?. BaseAmount/ name.ListQuoteBenefits [k]?.QuoteDetails?. BaseAmount*100-100] :”0.##”>> %<</if>>||<<[ name.ListQuoteBenefits [k]?.QuoteDetails?. PricePerUnit] :”0.##”>>||<<[ name.ListQuoteBenefits [k]?.QuoteDetails?. BaseAmount] :”0.##”>>||<<if [ name.ListQuoteBenefits [k]?.QuoteDetails?. BaseAmount != null && name.ListQuoteBenefits [k]?.QuoteDetails?. BaseAmount != 0]>><<[ name.ListQuoteBenefits [k]?.QuoteDetails?. BaseAmount/ name.ListQuoteBenefits [k]?.QuoteDetails?. BaseAmount*100-100] :”0.##”>> %<</if>><</foreach>>|
Here’s the final result:
Of course, with a licensed version of Aspose, there would be no watermark in the background!
Building an Azure project
Now let’s take a look at the 5 steps involved in building the project.
1. Create an Azure function
First, create an Azure function by following this tutorial: https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-your-first-function-visual-studio
2. Deploy the function
Then, deploy it in Azure and make sure it runs.
a) Right-click on the Azure function project and select Publish.
How to publish
b) In the options, make sure to stay in the Consumption Plan. As you can see here, the Premium Plan has no cold starts. For a project like this one, I’ve found that a cold start takes about 18 seconds.
3. Add Aspose.Words
Then add the Aspose.Words package from NuGet.
a) To do so, right-click and select Manage NuGet Packages.
Go to NuGet Package manager
b) Once there, find Aspose.Words and add it.
Of course, instead of Uninstall, you’ll see Install (I already have Aspose.Words installed).
4. Store Word templates in a stored class
To store Word templates in Azure, I opted to put them in a class stored as a Base64 string. You can read all the Word templates using an iterative process like this and then encode them as follows:
5. Use a POST request
The reason I didn’t use a GET request is because the URL seems limited in length to around 2,048 characters. I opted for a POST request instead. That way, there’s no limit because we can use the document body as a template. However, we have to configure the Azure function to accept CORS (Cross-Origin Resource Sharing).
This is done in the Azure portal by following the two steps below:
a) First, add your Dataverse URL in the CORS origin. You can get the URL from the Power Platform admin center (microsoft.com).
b) Then, open the function in the Azure portal and add the Dataverse URL as an accepted origin.
And there you have it!
Building a Dataverse project
Now let’s look at the Dataverse solution, which shares the model project. Here are two options available to you:
1. The AJAX method
We can make a POST request using AJAX, but this returns the results in the query area rather than a web page. However, the results of the AJAX request can be fed to the out-of-the-box Dataverse Jscript function to download the file to disk, thus saving the report.
You should replace createpdfusingasposeword with the name of your own Azure function and include jQuery in the location where your function is called from (form or list of records) so that the $.ajax is available.
2. Use a plug-in
We can also use a plug-in, namely a Dataverse library. In fact, a Jscript function can trigger an action to fetch the JSON data and send them to the Azure function. The action can be triggered by an entity, a list of entities, or with no context at all. The command may be to get all entities of a certain type, for example, the list of accounts and their primary contacts. Since we cannot include NewtonSoft, we must use JsonSerializer, which is sufficient for our needs.
We also need to redefine all our models, since we can’t use the XRM SDK types in the Azure function. That said, it’s not very complicated.
Here’s a simple example:
Now, the Azure function will take the model JSON, and using the data and the corresponding Word document, create an output PDF document, which it will return to the Dataverse.
To the user, it looks very simple:
After working with Aspose.Words full time for 3 months now, I’ve found it a great product for generating reports using data models already used in websites. It can easily be used to create reports in the Dataverse and use an Azure function. Some other advantages are the reasonable license fees and the fast output speed.
But above all, it’s very easy to use and will save you a considerable amount of time. Enjoy!
This article was written by our expert Jean-François Fortin.
From the same author
Want to know more?