Intercept HTML5 Report Viewer API Call Parameters

23 posts, 1 answers
  1. Chris
    Chris avatar
    7 posts
    Member since:
    Mar 2014

    Posted 25 Nov 2014 Link to this post

    Is there any way to intercept the parameters passed to the default ReportsController, using the ReportFileResolver()?

    I have some configurable parameters to my report (start date, end date) but I am also passing the UserId, which I would like to not expose to the client and insert the parameter value on the server using the cookie. 

    Is this possible?

    Thank you.
  2. Answer
    Stef
    Admin
    Stef avatar
    3047 posts

    Posted 28 Nov 2014 Link to this post

    Hello Chris,

    In the report add a report parameter for the UserId, and make it hidden (Visible=false). Then you can use a custom report resolver, in which you obtain the report, deserialize it and set the Telerik.Reporting.Report object's ReportParameters["UserId"].Value.

    In general, the HTML5 Report Viewer is a client-side widget served only by a running Reporting REST service, which is dedicated to display already created reports. It is the service that manages the report state and resources.

    The client (viewer) sends string description of the requested report (the viewer'sreportSource.report value) to the service, and depending on the report resolvers in the service's CreateReportResolver method this string description will be resolved to a report source object.
    By default we provide ReportFileResolver and ReportTypeResolver. You can also create your own custom report resolvers.



    I hope the above information is helpful.

    Regards,
    Stef
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
  3. DevCraft banner
  4. Chris
    Chris avatar
    7 posts
    Member since:
    Mar 2014

    Posted 01 Dec 2014 in reply to Stef Link to this post

    Can you provide some code samples of what this might look like? There is some disconnect as far as what should be happening in the Resolvers Resolve() method and where I have access to the report source object.

    Thank you.
  5. Chris
    Chris avatar
    7 posts
    Member since:
    Mar 2014

    Posted 01 Dec 2014 in reply to Chris Link to this post

    How do I get the fileName to pass to the Resolve() method of my CustomReportResolver within the CreateReportResolver method? And why do I need to deserialize if I am only modifying the parameter collection on the ReportsController?
  6. Stef
    Admin
    Stef avatar
    3047 posts

    Posted 04 Dec 2014 Link to this post

    Hello Chris,

    The purpose of the custom resolver is to receive the report's string description from the client (the viewer's reportSource.report information), then let you create/get a report by using the received information and finally return a valid report source object. On the next calls the client sends further information about the report parameters (viewer's reportSource.parameters information), which is passed to the already custom resolved report source's Parameters collection.

    To set a report parameter's value from the custom resolver, the value must be passed directly to the report object's ReportParameters collection, as the later sent parameters values would overwrite the values if set through the resolved report source object's Parameters collection.

    Having the above into account in the custom resolver you need to get a report and set its parameters values through its ReportParameters collection. If the report is in XML format or in a TRDX file, you need to deserialize it to get the report object's ReportParameters collection.

    For example:
    • The client settings:
      <!-- the client -->
       $("#reportViewer1")
                      .telerik_ReportViewer({  
                          serviceUrl: "api/reports/",
                          templateUrl: '/ReportViewer/templates/telerikReportViewerTemplate-8.2.14.1107.html',
                          //ReportSource - report description
                          reportSource: {                   
                              report: "GetReport1ByThisString",
       
                              // Parameters name value dictionary
                              parameters: {EndDate:'#1/1/2015#'}
                          },
                          scale: 1.0,                
                          }
           });
    • Then on the server
      using System.Web;
      using Telerik.Reporting.Cache.Interfaces;
      using Telerik.Reporting.Services.Engine;
      using Telerik.Reporting.Services.WebApi;
       
       
       
      public class CustomReportResolver : Telerik.Reporting.Services.Engine.IReportResolver
      {
          public Telerik.Reporting.ReportSource Resolve(string reportId)
          {
             //custom method you need to implement to get a report in XML or as Telerik.Reporting.Report object
             //in this example reportId will be 'GetReport1'
             var report = GetReport(reportId);
                   
       
            //if the report is in XML format, you need to implement a logic to deserialize the report
           Telerik.Reporting.Report reportObject;
           if(report is Telerik.Reporting.Report)
               reportObject = report;
          else
                reportObject = Deserialize(report);
       
            //get the information you need and pass it in the report
            var userId= GetUserFromCookie();
            reportObject.ReportParameters["UserId"].Value = userId;
       
              //return a valid report source
              return new Telerik.Reporting.InstanceReportSource{ ReportDocument= reportObject};
          }
      }
       
      public class ReportsController : ReportsControllerBase
      {
          protected override IReportResolver CreateReportResolver()
          {
               //the custom resolver will be used
              return new CustomReportResolver();
          }
       
          protected override ICache CreateCache()
          {
              return Telerik.Reporting.Services.Engine.CacheFactory.CreateFileCache();
          }
      }

    Regards,
    Stef
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
  7. JULIO
    JULIO avatar
    3 posts
    Member since:
    Nov 2011

    Posted 27 Feb 2015 in reply to Stef Link to this post

    how do you implement this function 'GetUserFromCookie' ?

    Please put the example?
  8. Stef
    Admin
    Stef avatar
    3047 posts

    Posted 02 Mar 2015 Link to this post

    Hello Julio,

    The code snippet is an example of the flow of operations. The GetUserFromCookie method must be replaced with your custom implementation for retrieving the user's information.

    Regards,
    Stef
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
  9. Kasun
    Kasun avatar
    16 posts
    Member since:
    Oct 2016

    Posted 21 Oct in reply to Stef Link to this post

    Hi Stef, With regards to the code above, is there any way where I can get the EndDate parameter and its value out in the server side? I basically want to keep track of all the parameters. So when i return the report from the server side, I sould be able to get teh parameters sent by the report viewer and save it somewhere in the database.  
  10. Stef
    Admin
    Stef avatar
    3047 posts

    Posted 24 Oct Link to this post

    Hi Kasun,

    You can:
    1. Use the report's ItemDataBindingg event to get the running values of report parameters e.g.:
      void report_ItemDatabinding(object sender, EventArgs e)
      {
          Telerik.Reporting.Processing.Report processingReport = (Telerik.Reporting.Processing.Report)sender;
          object processingParametes = processingReport.Parameters;
      }
    2. Get the client (viewer) reportSource.parameters collection via Javascript after the user clicks the 'Preview' button.
    3. Use entirely custom UI to pass values to report parameters. Thus you have full control over the input and its validation. For example, How To: Pass Values to Report Parameters.


    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
  11. Kasun
    Kasun avatar
    16 posts
    Member since:
    Oct 2016

    Posted 24 Oct in reply to Stef Link to this post

    Thanks Stef, 

    I will try this out and let you know. Thank you for the information. 

     

     

  12. Kasun
    Kasun avatar
    16 posts
    Member since:
    Oct 2016

    Posted 24 Oct in reply to Stef Link to this post

    Hi Stef, 

    I have one more question for you. Can we get the parameters in the Resolve method itself? In my scenario, I dont have a direct code behind to get databind method. Our UI is standalone and it will call bunch of services to get data. telerik Reporting service is one of them. So If I can get the parameters out in the resolve method, i can achieve my goal. 

    Could you please advice? 

     

  13. Stef
    Admin
    Stef avatar
    3047 posts

    Posted 25 Oct Link to this post

    Hi Kasun,

    Please check How to display a report via InstanceReportSource in the HTML5 Viewer.
    In general:
    1. The viewer has a client-side ReportSource, from which we extract the string description of the report (relative path to a TRDP|TRDX file), the assembly qualified name of a report class (<namespace>.<report_class>, <assembly_name>) or custom string (almost anything can be included with respect to REST limitations for used characters and size of the message).
    2. The reports string description is submitted to the server and it is handled by the Reporting REST service's Resolver. The service's default resolvers can handle a relative path to a TRDP|TRDX files or an assembly qualified name of a report class. Anything else requires you to create a custom resolver that returns a server-side ReportSource object on its own. A custom string allows you to send any information you need to the server.
    3. Once the Report resolver returns the server-side ReportSource object, the viewer submits the Parameters collection of its client-side ReportSource. This Parameters collection is applied as the server-side's ReportSource.Parameters collection. Thus the client-side reportsource.Parameters collection is not available in the service's resolver.
    4. Next, the reporting engine starts processing the report, means the report events fire, expressions are evaluated. At that moment the server-side ReportSource.Parameters collection is mapped to the report's ReportParameters collection - where Name properties (case sensitive) are the same, values are set for the report parameters.
    5. Finally, the report is rendered and paged in the requested format (HTML for web preview, PDF for export and etc.), and the content id returned to the client(viewer).

    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
  14. Kasun
    Kasun avatar
    16 posts
    Member since:
    Oct 2016

    Posted 25 Oct in reply to Stef Link to this post

    Thanks Stef for the information. I will try to implement this and get back to you. Thank you for your prompt response. Appreciate it.
  15. Kasun
    Kasun avatar
    16 posts
    Member since:
    Oct 2016

    Posted 03 Nov in reply to Stef Link to this post

    Hi Stef, 

     

    Im trying to implement the HTML 5 Report viewer with ASP.NET Core. My setup is little bit different than your samples.
    I have a completely separate REST service to read the DB and Return the Report File (InstanceReportSource) to the Viewer. So the Viewer is in a different solution , project altogether. Im having trouble with the template Url. When I give my Rest Service URL in the "serviceUrl", the viewer is trying to find the template also in that Rest service.

    I have the below code

     $(document).ready(function () {
                alert('Doc Ready');
                $("#reportViewer1")
                    .telerik_ReportViewer({
                        // The URL of the service which will serve reports.
                        // The URL corresponds to the name of the controller class (ReportsController).
                        // For more information on how to configure the service please check http://www.telerik.com/help/reporting/telerik-reporting-rest-conception.html.
                        serviceUrl: 'http://localhost:54992/reportingengine/reports',

                        // The URL for the report viewer template. The template can be edited -
                        // new functionalities can be added and unneeded ones can be removed.
                        // For more information please check http://www.telerik.com/help/reporting/html5-report-viewer-templates.html.
                        @*templateUrl: '@Url.Content("~/resources/templates/telerikReportViewerTemplate.html")',*@                    
                        //ReportSource - report description
                        reportSource: {

                            // The report can be set to a report file name
                            // or CLR type name (report class definition).
                            report: "3",

                            // Parameters name value dictionary
                            parameters: {}
                        },

                        // Specifies whether the viewer is in interactive or print preview mode.
                        // PRINT_PREVIEW - Displays the paginated report as if it is printed on paper. Interactivity is not enabled.
                        // INTERACTIVE - Displays the report in its original width and height without paging. Additionally interactivity is enabled.
                        viewMode: telerikReportViewer.ViewModes.INTERACTIVE,

                        // Sets the scale mode of the viewer.
                        // Three modes exist currently:
                        // FIT_PAGE - The whole report will fit on the page (will zoom in or out), regardless of its width and height.
                        // FIT_PAGE_WIDTH - The report will be zoomed in or out so that the width of the screen and the width of the report match.
                        // SPECIFIC - Uses the scale to zoom in and out the report.
                        scaleMode: telerikReportViewer.ScaleModes.SPECIFIC,

                        // Zoom in and out the report using the scale
                        // 1.0 is equal to 100%, i.e. the original size of the report
                        scale: 1.0,
                    });
            });

     

    So as you can see, my service Url is a separate rest service. Can we do something like this at all? Also do we need to add any Telerik references in to the report viewer client side code?  

  16. Kasun
    Kasun avatar
    16 posts
    Member since:
    Oct 2016

    Posted 03 Nov Link to this post

    Hi Stef, 

    Disregard my earlier post. I got it working. But I have another issuer now. 

    I have my Reports Controller, Inherits from ReportsControllerBase. Also I have written a customResolver using inheriting from IReportResolver.

    My Resolve method has a string parameter

    public ReportSource Resolve(string reportId)
    {

    //My Custom Logic

    }

    In the Reports controller, I have overridden the CreateReportResolver returning IReportResolver  and CreateStorage returning IStorage methods. 

     

    When I call from the Report Viewer, the call comes to the Report controller, but it never hits the Resolve method in my customResolver. 

    And the Report Viewer says Error creating report instance (Report = 3).undefined

    3 is what I pass as ReportSource in the viewer. 

    Any thoughts on this? 

     

     

  17. Stef
    Admin
    Stef avatar
    3047 posts

    Posted 04 Nov Link to this post

    Hi Kasun,

    Please compare the your implementation of the ReportsControllerBase with the suggested here. At the place of the ReportResolver property you can create a new instance of the custom resolver.

    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
  18. Kasun
    Kasun avatar
    16 posts
    Member since:
    Oct 2016

    Posted 04 Nov in reply to Stef Link to this post

    Hi Stef, Im following the exact same steps. The only difference in my architecture is my report viewer is separated from the Rest service. As I mentioned earlier, My report viewer project is in a separate solution. My rest service is a separate service. Im calling the Rest service full URL from the viewer. 

    So I have tried to intercept the calls using fiddler, There are mainly 3 calls are happening. They are ;

    [baseUrl]/api/reports/clients 

    Response 200 OK. 

    [baseUrl]/api/reports/clients/{myclientId}/parameters

    Response 415 Unsupported Media Type

    [baseUrl]/api/reports/clients/{myclientId}/instances
    Response 415 Unsupported Media Type

     

    I have no idea why im getting unsupported media type for those 2 calls. Do we need to specify any special formatters in startup class?  

    I was checking this article. but Im not getting the mentioned mvc6 formmaters in my current nuget package. I suppose this article is an old one. 

    Im using below nuget packages which i got from telerik site

    Telerik.Reporting.Services.AspNetCore.trial.nupkg

    Telerik.Reporting.Trial.nupkg

    I look forward to hearing form you. 

    Thanks.

  19. Stef
    Admin
    Stef avatar
    3047 posts

    Posted 04 Nov Link to this post

    Hi Kasun,

    Please check the CHM file (local documentation) of the used Telerik Reporting version. Search for "HTML5 Report Viewer in ASP.NET Core". The article will contain the supported scenarios and valid settings for the version. The CHM can be downloaded from your Telerik account - Downloads - Reporting.

    If the project is updated to use ASP.NET Core, you will need to update Telerik Reporting packages with a version of R3 2016 or newer (the latest information in HTML5 Report Viewer in ASP.NET Core). The attached demo project is built based on the linked article.

    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
  20. Kasun
    Kasun avatar
    16 posts
    Member since:
    Oct 2016

    Posted 04 Nov in reply to Stef Link to this post

    Hi Stef, 

    Thank you for the reply. I found the issue. The issue was a cross origin access issue. I had to open those settings in my REST service. Now its going to the resolve method and i was able to display a simple parameter less report in the viewer. Yeey :)

    I still have to figure out why there are multiple calls coming to the rest service. When i load the report viewer, Im getting like 3 hits to the resolve method. Do you have any thoughts on that?

    On a separate note, the report viewer is working with my custom build REST service now. I will get more road blocks when it comes to parameters and dynamic data sources like CUBEs. I will sure contact you :). Thank you for your help.

    If anyone wants to know how to enable cross origin in ASP.NET Core, Follow below steps

    In startup.cs class, in Configure method, add the below 
     

    app.UseCors(builder =>
          {
              builder
                  .AllowAnyOrigin()
                  .AllowAnyHeader()
                  .AllowAnyMethod()
                  .AllowCredentials()
                  .Build();
          });

     

    Also add Microsoft.AspNet.WebApi.Cors nuget package to the project. 

  21. Stef
    Admin
    Stef avatar
    3047 posts

    Posted 07 Nov Link to this post

    Hi Kasun,

    Thank you for this update.
    These asp.net articles may be helpful as well - Enabling Cross-Origin Requests (CORS) (ASP.NET Core) and Enabling Cross-Origin Requests in ASP.NET Web API 2. The settings depend on the type of project hosting the Reporting REST service.


    About the custom resolver, it is called multiple times on interaction with the viewer - initial displaying, applying of parameters, viewer refreshes, parameters updates, export and print, navigation to other reports. All of these requests are handled on the server where the service is running. The information received in the custom resolver is the string describing the requested report.


    About using the CubeDataSource component, please check Configuring your project for using Microsoft Analysis Services and the related articles. The settings go in the project of the Reporting RESt service as reports are processed and rendered server-side.

    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
  22. Kasun
    Kasun avatar
    16 posts
    Member since:
    Oct 2016

    Posted 07 Nov in reply to Stef Link to this post

    Thank you Stef for the reply.
  23. Kasun
    Kasun avatar
    16 posts
    Member since:
    Oct 2016

    Posted 17 Nov Link to this post

    HI Stef, I know the report viewer sends like 6 requests to the reportApi (To the service which has my custom resolver) in order to display a full report. Is there anyway we can reduce that? Because We have a SOA environment.When a hit comes to ReportApi, there will be another 5 service calls going out from the ReportApi to gather necessary information. Which will lead to a potential performance issue. I know there is a necessity to call the reportApi like 5 times when rendering a report. I just wanted to check with you if there is anything I'm missing. 

    Apart from that,We are setting request header in the view using "ajaxPrefilter" so all the calls will have our custom header. But I notice, the last call comes without the header. I used Fiddler to catch the request.

    [MyBaseUrl]/reports/clients/172022-30c7/instances/165827-493d/documents/172028-86d4172029-3f8e/resources/115ac0b99c974258a03b9eeb7cbe21b3/

    This request comes in the end without the header. Could you please help me to solve these questions ?

    Thank you Stef.

     

  24. Stef
    Admin
    Stef avatar
    3047 posts

    Posted 21 Nov Link to this post

    Hello Kasun,

    The Reporting REST service's resolver is called initially on getting information about parameters, on creating an instance on the server, and on requesting the report in a specific format (HTML for the web preview). Then the resolver is called on changes in report parameter's values (any changes on the viewer's ReportSource at the client), export, print, navigation between reports, refresh of the viewer ( includes the viewer's RefreshButton and direct calls to the viewer's refreshReport method).

    If you are getting data in the resolver, consider implementing custom cache to hold the information once it is retrieved for first time. If it is only about settings data in the report, you can use and the report's NeedDataSource event - Using Report events. The event is called only if the data item does not have a value for its DataSource.


    About requests for resources, please upgrade to the latest possible version where resources requests are done via AJAX requests handled by the Reporting REST service's GetResource method - ReportsControllerBase methods. Details how to add headers are discussed here.

    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
Back to Top
DevCraft banner