How to use Online Designer with FastReport.Core Library

Posted by quetz67 on Thu, 09 May 2019 20:58:02 +0200

Download the latest version of FastReport.Net

Many FastReport.Core users are interested in how report generators work in Web applications written using React libraries. In this article, we will introduce how to use an online designer. Although it is displayed in the same Web object as a regular report, it is quite different from what is shown in React.

If you have never created an application on the back end of. Net Core on React, you need:

1) Install NodeJS. This is a software package that allows you to execute JavaScript code on the server side and install various JavaScript libraries.

2) Install Microsoft Visual Studio 2017 or other IDE + Net Core SDK 2.0.

To create an application, open the Windows command prompt in the folder where the project is located, and then execute the following commands:

dotnet new react -o ReactFRCoreDesigner

Open the created project. Let's add the FastReport library to the NuGet package manager. Configure the folder's local package source:

C: \ Program Files(x86)\ FastReports \ FastReport.Net \ Nugets

Install the FastReport.Core package.

Find the Startup.cs file in the project and add a line of code to the Configure () method:

app.UseFastReport();

Now we can use report generator in our project.

In addition to displaying the online designer, we also look at the way the report name is transmitted and upload it to the online designer. Therefore, we add the App_Data folder to the project. In it, we will add report templates from the Demos Reports folder in the FR.Net installation directory.

As you can see, we also added an xml file from the same folder. This is a report database.

Find the Controllers folder. We can use the SampleData Controller controller. Add two methods:

...
using FastReport.Web;
using System.IO;
...
[HttpGet("[action]")]
 public IActionResult Design(string name)
 {
 WebReport WebReport = new WebReport();
 WebReport.Width = "1000";
 WebReport.Height = "1000";
 if (name != "Blank")
 WebReport.Report.Load("App_Data/" + name + ".frx"); // Load the report into the WebReport object
 System.Data.DataSet dataSet = new System.Data.DataSet(); // Create a data source
 dataSet.ReadXml("App_Data/nwind.xml"); // Open the database xml
 WebReport.Report.RegisterData(dataSet, "NorthWind"); // Registering the data source in the report
 
 WebReport.Mode = WebReportMode.Designer; // Set the web report object mode - designer display
 WebReport.DesignerLocale = "en";
 WebReport.DesignerPath = @"WebReportDesigner/index.html"; // We set the URL of the online designer
 WebReport.DesignerSaveCallBack = @"api/SampleData/SaveDesignedReport"; // Set the view URL for the report save method
 WebReport.Debug = true;
 ViewBag.WebReport = WebReport; // pass the report to View
 return View();
 }
 
 [HttpPost("[action]")]
 // call-back for save the designed report
 public IActionResult SaveDesignedReport(string reportID, string reportUUID)
 {
 ViewBag.Message = String.Format("Confirmed {0} {1}", reportID, reportUUID); // Set the message for representation
 Stream reportForSave = Request.Body; // Write the result of the Post request to the stream.
 string pathToSave = @"App_Data/TestReport.frx"; // get the path to save the file
 using (FileStream file = new FileStream(pathToSave, FileMode.Create)) // Create a file stream
 {
 reportForSave.CopyTo(file); // Save query result to file
 }
 return View();
 }

The first method is to create Web report object, set template and data source for it, set report editing mode and report designer settings. Therefore, this method returns the view that will display the Web report object. This method has a parameter - the name of the report, which we replace when loading the report template into the Web object of the report.

The second method is a callback handler for clicking the report save button. It saves the edited report in the App_Data folder.

For both approaches, you must create two views. Create a Views folder in the project root directory. Now go back to the controller. Right-click Design Method Signature, and then select Add View from the menu. Set View Name - Design. Replace the entire content of the created view with code:

@await ViewBag.WebReport.Render()

For the Save Designed Report method, we also created a view with the same name. Its contents are replaced by:

@ViewBag.Message

We turned to the front end. The React application is located in the ClientApp folder. Expand it in the solution browser tree. Further, we open the src and components directories. Add new components to this folder. Create a javascript file named Designer:

import React, { PureComponent, Fragment } from 'react';
import { WebReport } from './WebReport';
 
export class Designer extends PureComponent {
 constructor(props) {
 super(props);
 this.state = {
 options: [
 {
 value: 'Select report name ...',
 },
 {
 value: 'Matrix',
 },
 {
 value: 'Master-Detail',
 },
 {
 value: 'Text',
 },
 ]
 };
 } 
 
 handleChange = (event) => {
 this.setState({ name: event.target.value }); 
 };
 
 render() {
 const { options, value } = this.state;
 return (
 <div>
 <div>
 <Fragment>
 <select onChange={this.handleChange} value={value}>
 {options.map(item => (
 <option key={item.value} value={item.value}>
 {item.value}
 </option>
 ))}
 </select>
 </Fragment>
 </div>
 <WebReport name={this.state.name} />
 </div>
 );
 }
 }

Note the import of the Web Report component.

First, add the state to the class constructor. In our example, it is an array containing the report name. Next, consider render () - the way to build a web page. Rendering is performed every time the state changes. For example, when we select a list item, the onChanges event handler is executed. This method uses the setState function to set the new state of the name variable. After that, the rendered content will be rebuilt.

Note the <WebReport name = {this.state.name}/> tag.

Another component is called here. As a parameter, it receives the selected report name.

Considering the Web Report component, it should also be like Designer.js created in the components directory:

import React, { Component } from 'react';
 
export class WebReport extends Component {
 constructor(props) {
 super(props);
 this.state = { designer: "" };
 }
 
 componentWillReceiveProps(nextProps) {
 fetch('api/SampleData/Design?name=' + nextProps.name + '').then(response => response.text()).then(text => {
 this.setState({ designer: text });
 });
 };
 
 render() {
 return (
 <div dangerouslySetInnerHTML={{ __html: this.state.designer }} />
 );
 }
}

The focus of this component is to execute the'get'request on the back end and return the generated html code.

The built-in function componentWillReceiveProps (nextProps) is executed every time the props attribute changes. That is, when this component is invoked, it receives a new value. We get the report name from the property and replace it with the requested URL. We get the answer in text format. It needs to be converted to secure html code to be inserted into the DOM. The dangerouslySetInnerHTML attribute will help us solve this problem.

It still just adds the Designer component to the menu. Add to NavMenu file:

<Navbar.Collapse>
 <Nav>
 ...
 <LinkContainer to={'/designer'}>
 <NavItem>
 Designer
 </NavItem>
 </LinkContainer>
 </Nav>
</Navbar.Collapse>

And add in App.js file:

...
import { Designer } from './components/Designer';
...
 <Layout>
...
 <Route path='/designer' component={Designer} />
 </Layout>
...

Running the application, on the Designer page, we will see a drop-down list:

Select the name of the Matrix report:

Now click Master-Detail:

Go to the Report tab and click the Save button:

A "saved" message appears on the right, telling us that the report was successfully saved on the server.

Another file appears in the App_Data folder - TestReport.frx.

This completes the creation of our demo application. We successfully displayed the report designer, loaded the necessary reports into it and saved them.

Related links:

Topics: ASP.NET React Javascript xml Fragment