This is a migrated thread and some comments may be shown as answers.

HTML5 Report Viewer - Custom Error Message from Custom Report Resolver

13 Answers 856 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Thomas
Top achievements
Rank 1
Thomas asked on 09 Jul 2015, 07:49 AM

Hello Community

 I am working with Reporting using HTML5 Report Viewer. I have designed Custom Report Resolver for showing up the reports. It works like a charm. I am facing issue regarding how to pass custom error message from Report Controller. I have checked some links regarding localization given in forums which says to add JS files but i am not exactly getting how to proceed. Can someone provide code sample?

13 Answers, 1 is accepted

Sort by
0
Stef
Telerik team
answered on 09 Jul 2015, 03:54 PM
Hello Thomas,

You can subscribe in the report for its Error event and you will be able to log errors during the processing of the report.

To get the server error message on displaying the report in the HTML5 Report Viewer, the viewer also exposes an error event where you can get the actual error message and include logic for further handling (hide the viewer, display a message, and etc.). The errors caught here are errors thrown during the report processing on the server or errors occurring during the information exchange between the client(viewer) and the service.
For example:

$(document).ready(function () {
       $("#reportViewer1")
           .telerik_ReportViewer({
               serviceUrl: "api/reports/",
               templateUrl: 'ReportViewer/templates/telerikReportViewerTemplate-9.1.15.702.html',
               reportSource: {
                   report: "Telerik.Reporting.Examples.CSharp.ReportCatalog, CSharp.ReportLibrary",
                   parameters: { }
               },
               viewMode: telerikReportViewer.ViewModes.INTERACTIVE,
               scaleMode: telerikReportViewer.ScaleModes.SPECIFIC,
               scale: 1.0,
              error: function (e, args) {
                   log(args);
                   alert('The error indicates an issue with ' + args);
               }
           });
   });


I hope the provided information is helpful.

Regards,
Stef
Telerik
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
0
Thomas
Top achievements
Rank 1
answered on 09 Jul 2015, 06:28 PM

Thanks for the quick response.

I had seen in documentation regarding error event. But i was not sure that we need to throw exception from server side for appropriate message to show on client side.

here it shows that if we add this js in application we can show messages given there. can we add our custom message in this JS and how these messages will be retrieved from JS?

0
Stef
Telerik team
answered on 10 Jul 2015, 04:12 PM
Hi Thomas,

Below is an update from your support ticket on the same question:

"If there are errors during the report processing, they can be caught in the report's Error event which event arguments allow you to Cancel the further execution of the report and throw a custom error message that will be seen at the client.
//the report
  public partial class rptTest : Telerik.Reporting.Report
    {
        public rptTest()
        {
            //
            // Required for telerik Reporting designer support
            //
            InitializeComponent();
             this.Error += new Telerik.Reporting.ErrorEventHandler(this.rptTest_Error);
            //
            // TODO: Add any constructor code after InitializeComponent call
            //
        }
 
        private void rptTest_Error(object sender, ErrorEventArgs eventArgs)
        {
            eventArgs.Cancel = true;
            throw new Exception("manually cancelled");
        }
    }
 
 
//////////////////////////////////////
//the client
 
$(document).ready(function () {
       $("#reportViewer1")
           .telerik_ReportViewer({
               serviceUrl: "api/reports/",
               templateUrl: 'ReportViewer/templates/telerikReportViewerTemplate-9.1.15.702.html',
               reportSource: {
                   report: "Telerik.Reporting.Examples.CSharp.ReportCatalog, CSharp.ReportLibrary",
                   parameters: { }
               },
               viewMode: telerikReportViewer.ViewModes.INTERACTIVE,
               scaleMode: telerikReportViewer.ScaleModes.SPECIFIC,
               scale: 1.0,
              error: function (e, args) {
                  $('.trv-error-pane').toggle();
                  alert(args);
                  console.log("error!");
               }
           });
   });


About the error messages listed in HTML5 Viewer Localization, you can change only the string next to the identifier of the error. Extending the error list with custom entries is not supported."

Regards,
Stef
Telerik
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
0
Ian
Top achievements
Rank 1
answered on 28 Jun 2016, 04:24 PM

Hi,

I have tried implementing the custom report class by inheriting Telerik.Reporting.Report as suggested here but InitializeComponent() cannot be found and Me.Error is an event that cannot be assigned to directly. (I am using VB).

Can you suggest how I can customise the error message that is appearing in the report viewer when an exception is thrown from my customReportResolver.Resovle() function?

I am setting my reportsource and serviceurl in the code behind so cannot add the client side error tag in Javascript as suggested in this thread:  http://www.telerik.com/forums/custom-report-resolver-exception 

 

0
Stef
Telerik team
answered on 30 Jun 2016, 08:54 AM
Hello Grant,

The report's Error event will be fired if there is an error during the report processing. Such exceptions are returned to the client by the viewer, and they can be handled further in the viewer's error event.
The viewer's error event can be used for handling errors on registering the viewer or other related to the connection with the Reporting REST service specified by the viewer's serviceUrl.

About errors result of resolving a report in a custom resolver, the thrown Exception will not be bubbled directly to the viewer. Actually, there will be an error on the attempt to get parameters information (the first request the viewer will send on displaying a report) - the request will go through the custom resolver's Resolve method and it will return an error, which can be handled by overriding the ReportscontrollerBase GetParameters method:
public override System.Net.Http.HttpResponseMessage GetParameters(string clientID, ClientReportSource reportSource)
{
    try {
        return base.GetParameters(clientID, reportSource);
    } catch (Exception ex) {
        throw new Exception("report resolving failure.");
    }
}


I hope this helps.

Regards,
Stef
Telerik
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
0
János
Top achievements
Rank 1
answered on 12 Jul 2016, 12:19 PM

Hi 

I would like to know if this approach would also work in a scenario where I'm using .trdx files instead of Csharp class ones?

(in a .net MVC project)

//the report
  public partial class rptTest : Telerik.Reporting.Report
    {
        public rptTest()
        {
            //
            // Required for telerik Reporting designer support
            //
            InitializeComponent();
             this.Error += new Telerik.Reporting.ErrorEventHandler(this.rptTest_Error);
            //
            // TODO: Add any constructor code after InitializeComponent call
            //
        }
  
        private void rptTest_Error(object sender, ErrorEventArgs eventArgs)
        {
            eventArgs.Cancel = true;
            throw new Exception("manually cancelled");
        }
    }
  
  
//////////////////////////////////////
//the client
  
$(document).ready(function () {
       $("#reportViewer1")
           .telerik_ReportViewer({
               serviceUrl: "api/reports/",
               templateUrl: 'ReportViewer/templates/telerikReportViewerTemplate-9.1.15.702.html',
               reportSource: {
                   report: "Telerik.Reporting.Examples.CSharp.ReportCatalog, CSharp.ReportLibrary",
                   parameters: { }
               },
               viewMode: telerikReportViewer.ViewModes.INTERACTIVE,
               scaleMode: telerikReportViewer.ScaleModes.SPECIFIC,
               scale: 1.0,
              error: function (e, args) {
                  $('.trv-error-pane').toggle();
                  alert(args);
                  console.log("error!");
               }
           });
   });

 

0
Stef
Telerik team
answered on 12 Jul 2016, 03:09 PM
Hi János,

Reports saved in TRDX|TRDP files have to be deserialized|unpackaged in order to be subscribed for their Error events. This can be done by using a custom resolver for the Reporting REST service.

Without subscribing the reports to their Error events, the processing error will be bubbled directly to the viewer's error event.

Regards,
Stef
Telerik by Progress
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
0
János
Top achievements
Rank 1
answered on 13 Jul 2016, 07:53 AM

Thank you for you fast answer Stef.

 

Sorry but i asked the wrong question, I ased about Error handling but what I realy wanted to know is Exception handling.

We currently want to use TRDX files and also ObjectData source. It all works until there is an Exception thrown. Then it kind of displays a red Exception message inside the ReportViewer which I can't seem to get a hold of, nomatter what I try. (We also want to throw custom exceptions to let the user know whats wrong in a talkative error pop up message of some sort.

As i understood from the documentation it would be easier if we would just leave the idea of useing TRDX files and just use the Visual Studio report builder plugin. 

And my last question would be, is it even a good practice to throw exceptions in the objectdata class and let them bubble up to the ReportViewer, or should they be handled earlier?

 

Best regards

 

0
Stef
Telerik team
answered on 13 Jul 2016, 04:08 PM
Hello János,

You can keep using TRDX files, where in a custom resolver you can deserialize them and subscribe the produced Telerik.Reporting.Report instances to their Error events. In each Error event you can cancel the further processing and throw your own message. The message will be displayed in an yellow box in the viewer's page area. the error message can be further handled in the viewer's error event as well.

In case the error occurs in the data-retrieval method, you can throw an exception in it, which will be displayed in the report in a white box with red border.

Regards,
Stef
Telerik by Progress
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
0
János
Top achievements
Rank 1
answered on 18 Jul 2016, 01:49 PM

Hi Stef,

I've made some progress according to what you recommended. I'm very gratefull for your help sofar.
I made a custom resolver that serializes/unpacks the report files according to file type (trdx, or trdp)
Now I can sign up to the error event and also catch exceptions. 

 

But another problem arised becouse of my custom resolver. The Subreport paths seem to be broken.
Everything goes well until there is a subreport within a report.

 

The main report is located in a /ReportFiles folder and so is the subreport. While debuging I can see that the path for the main report is always valid at brakepoints. But the subreport doesn't even run in to brakepoints and the path is set to the root of the project by default for some reason.

 

As I understand the subreport is infact not going throug my custom resolver, nor is it going to the fallback resolver, but somewhere else. I'm a bit confused at this point.

Could you please help shine some light upon how subreports are being resolved? It would help me out a lot.

 

Best Regards

János

 

0
Stef
Telerik team
answered on 19 Jul 2016, 03:38 PM
Hi János,

If you are using the code from Changing the connection string dynamically according to runtime data
check the Report DeserializeReport(UriReportSource uriReportSource) method and verify the file path retrieved from the UriReportSource is mapped correctly on the server. You can use method like Server.MapPath in case of getting a relative file path.

Regards,
Stef
Telerik by Progress
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
0
János
Top achievements
Rank 1
answered on 21 Jul 2016, 02:43 PM

Hi Stef,

 

I managed to find the problem but, not the solution. The link what you've sent wasn't exactly the same situation that I have, but guided me in the right direction. (I don't intent to change the ConnectionString in runtime) Just want to resolve the main and the subreports from the same path.

But I seem to be missunderstanding something, I'll write down how I think the resolveing process goes. Please correct me if I am wrong in something.

 

Let's assume the reports (also the subreports) are in this path: C:\Project\ReportFiles

The resolving process goes as this:

-I request a report by file name: main.trdx

-The Custom or Regular Resolver steps in to action and returns the ReportSource.

-I deserialize/unpack the report and add an exepction handler to the error event. And return the ReportSource.

-The report has a subreport which is a type of ReportItemBase that also has a ReportSource.Uri. The main report tries to resolve the subreport by invoking a ReportResolver.And it fails if I deserialize the report.

It evaluates to main report:  C:\Project\ReportFiles\main.trdx (which is correct)

while the subreport is:  C:\Project\main.trdx (which is incorrect)

 

If I use the default resolvert it resolves both path just fine.

The only way i managed to get it working is by recursively chechking each and every ReportItemBase item of the main report to check if it is a SubReport item. And manualy resolve the subreport. Which I thought worked for onece but, it doesn't. Since I loose the parameters somehow. And also this method sounds very resource consuming and sub-optimal.

I'll paste my code:

public class ReportsController : ReportsControllerBase
{
    static ReportServiceConfiguration configurationInstance;
 
    static ReportsController()
    {
         
        var appPath = HttpContext.Current.Server.MapPath("~/");
        var reportsPath = Path.Combine(appPath, "/ReportFiles");
 
        var resolver = new CustomResolver2(reportsPath)
            .AddFallbackResolver(new CustomResolver(reportsPath));
 
        //Setup the ReportServiceConfiguration
        configurationInstance = new ReportServiceConfiguration
        {
            HostAppId = "Project",
            Storage = new FileStorage(),
            ReportResolver = resolver
            // ReportSharingTimeout = 0,
            // ClientSessionTimeout = 15,
        };
    }
 
    public ReportsController()
    {
        //Initialize the service configuration
        this.ReportServiceConfiguration = configurationInstance;
    }
 
}
 
 
class CustomResolver : ReportFileResolver
{
    public CustomResolver(string path) : base(path) { }
    protected override ReportSource ResolveReport(string report)
    {
        return base.ResolveReport(report);
    }
 
    public ReportSource GetReportSource(string report){
        return base.ResolveReport(report);
    }
}
 
class CustomResolver2 : ReportFileResolver
{
    private CustomResolver customResolver;
 
    public CustomResolver2(string path) : base(path) {
        customResolver = new CustomResolver(path);
    }
 
    public ReportSource GetReportSource(string report)
    {
        return base.ResolveReport(report);
    }
 
    protected override ReportSource ResolveReport(string report)
    {
 
        ReportSource reportSource = customResolver.GetReportSource(report);
 
 
        //TRDX
        if (report.Split('.').Last().ToLower().Equals("trdx"))
        {
            var uriReportSource = (UriReportSource)reportSource;
            var reportInstance = DeserializeReport(uriReportSource);
            FixSubreportPath(reportInstance);
            return CreateInstanceReportSource(reportInstance, uriReportSource);
        }
        //TRDP
        else
        {
            var uriReportSource = (UriReportSource)reportSource;
            var reportInstance = UnpackReport(uriReportSource);
            FixSubreportPath(reportInstance);
            return CreateInstanceReportSource(reportInstance, uriReportSource);
        }
    }
 
    void FixSubreportPath(ReportItemBase reportItemBase) {
 
        foreach (var item in reportItemBase.Items)
        {
            FixSubreportPath(item);
            if (item is SubReport)
            {
                var appPath = HttpContext.Current.Server.MapPath("~/");
                var reportsPath = Path.Combine(appPath, "/ReportFiles/");
 
                var subReport = (SubReport)item;
                var subUriReportSource = (UriReportSource)subReport.ReportSource;
 
                var cr = new CustomResolver2(reportsPath);
                 
 
                subReport.ReportSource = cr.GetReportSource(subUriReportSource.Uri);                                
            }
        }
         
    }
 
    ReportSource CreateInstanceReportSource(IReportDocument report, ReportSource originalReportSource)
    {
        var instanceReportSource = new InstanceReportSource { ReportDocument = report };
        instanceReportSource.Parameters.AddRange(originalReportSource.Parameters);
        return instanceReportSource;
    }
 
    Report DeserializeReport(UriReportSource uriReportSource)
    {
        var settings = new System.Xml.XmlReaderSettings();
        settings.IgnoreWhitespace = true;
        using (var xmlReader = System.Xml.XmlReader.Create(uriReportSource.Uri, settings))
        {
            var xmlSerializer = new Telerik.Reporting.XmlSerialization.ReportXmlSerializer();
            var report = (Telerik.Reporting.Report)xmlSerializer.Deserialize(xmlReader);

            report.Error += HandleError;

            return report;
        }
    }
 
    Report UnpackReport(UriReportSource uriReportSource)
    {
        var reportPackager = new ReportPackager();
        using (var sourceStream = System.IO.File.OpenRead(uriReportSource.Uri))
        {
            var report = reportPackager.Unpackage(sourceStream);
            return report;

            report.Error += HandleError;

        }
    }
 
 
 
    private void HandleError(object sender, Telerik.Reporting.ErrorEventArgs eventArgs)
    {
        throw new Exception("Exception: "+ eventArgs.Exception.Message);
    }
 
}

(I know CustomResolver is the same as a default resolver, its just for troubleshooting, And so is the GetReportSource method)


Thank you for you help

 

Best Regards

János

0
János
Top achievements
Rank 1
answered on 21 Jul 2016, 02:47 PM

Damn, I broke the code formating section...

 

And also made a mistake:

"It evaluates to main report:  C:\Project\ReportFiles\main.trdx (which is correct)
while the subreport is:  C:\Project\sub.trdx (which is incorrect)"

 

Thanks

Tags
General Discussions
Asked by
Thomas
Top achievements
Rank 1
Answers by
Stef
Telerik team
Thomas
Top achievements
Rank 1
Ian
Top achievements
Rank 1
János
Top achievements
Rank 1
Share this question
or