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

Accessing the ReportViewerModel in WPF

11 Answers 244 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Stephen McDaniel
Top achievements
Rank 1
Stephen McDaniel asked on 13 Mar 2017, 08:51 PM

We are in the process of creating a WPF version of our application that is already written in Silverlight.  We rely on Telerik controls across our entire UI and we've been very happily surprised with just how easy that process has been thanks to the common interface between Telerik's SL and WPF controls.

However, we have started porting over our logic that deals with the Report Viewer control and have noticed that the ReportViewerModel class is internal in WPF whereas it is public in Silverlight.  I've read many forum posts that talk about how the ReportViewerModel class is meant for internal use and can change at any point.  Despite that, we've very happily depended on the ReportViewerModel class because we do a lot of 'deep' integration with the Report Viewer.  If the internal structure of the Report Viewer changes, we aren't surprised if we need to tweak our code and just accept that as the cost of being tightly coupled with the Telerik controls (on a side note, we have the same situation with the Telerik Grids and other controls where we are also deeply integrated).

In reading through other forum posts, I know you tend to point people towards using methods on the Report Viewer instead of going to the model.  I briefly looked into that but there are some functions that just don't seem exposed on the Report Viewer (one example is setting IsExportEnabled on the model which doesn't seem to have any corresponding way to set that from the Report Viewer).

Even if there were ways that we could change our logic to avoid using the ReportViewerModel, I'd still feel much more comfortable if our existing code that has been heavily tested and scrutinized could 'just work' in WPF.  We want to avoid as many major refactorings as possible and it seems like we could avoid a whole bunch of headaches if this class could be public like it is in SL.

11 Answers, 1 is accepted

Sort by
0
Stef
Telerik team
answered on 14 Mar 2017, 12:41 PM
Hi Stephen,

The WPF ReportViewer's model is not exposed intentionally to avoid its usage and possible problems on upgrade. The model can be changed at any time resulting in entirely not working applications.
Thus we exposed the viewer's API to provide access to the viewer without breaking applications when we need to change something internally.

The exposed API.

You can use the RenderingEnd event to get when the report is rendered and loaded in the viewer, allowing you to call the ExportReport method.


We will appreciate any feedback on lacking functionality, or features not available in the exposed API. Also we recommend using the Silverlight Report Viewer's exposed API.


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
Stephen McDaniel
Top achievements
Rank 1
answered on 17 Mar 2017, 09:43 PM

That's not the answer I was hoping for but I can understand the desire to keep the class internal.  I'm curious if there is just some technical reason that the Silverlight version of that class is public....but I won't complain about that since others (like us) might be relying on that class in their Silverlight app.

I think I may not have explained the one use case well in my first post.  I know how to programmatically export a report.  The thing that I'm trying to do is enable the standard Export function in the Report Viewer....even in cases where the report viewer wants to disable it.  That use case is one of the times we currently access the model - to set IsExportEnabled to true when it would otherwise be false.  That is something that I don't see in the exposed API but we would need that.

I'll continue looking for other things that we would need added to the exposed API.  Thanks!

0
Stef
Telerik team
answered on 22 Mar 2017, 01:17 PM
Hello Stephen,

Based on my knowledge, in Silverlight the model cannot be hidden, which is the reason for it to remain public. There are no plans of changing this behavior of the Silverlight ReportViewer.

About the WPF ReportViewer, the export should be disabled during the report processing, refresh and update operations. Also if the selected export option is not listed in the RenderingExtensions of the viewer. Please elaborate on the usage of the property in you code with examples.

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
Stephen McDaniel
Top achievements
Rank 1
answered on 22 Mar 2017, 09:24 PM

Here is the specific scenario where we set IsExportEnable (note that this is how it works with the Silverlight viewer.  I'm not sure this applies to WPF but that's just because I haven't tested there as we haven't finished porting our app to WPF):

  1. User runs a report.  The first page of the report is returned in the Report Viewer
  2. Something happens on the web server that causes the report to expire.  For us, I think that would happen if the web server decided it needed to recycle/restart.  Maybe there are other reasons the report could expire.
  3. User clicks to page 2 of the report.  Since the report expired on the server, the Report Viewer shows a message about the report being expired and then basically all the buttons (including Export) in the viewer are disabled.

I can understand that behavior because it makes sense in most cases.  However, in our app we want the export button to still be available because there is no reason the user can't still export the report.  In our SL code, we can just set the IsExportEnabled property to true (and I think we tweak the 'report is expired' message) and now the user can choose to Export the report even though the report expired (which is not really something the user understands anyway).  Everything with the export works fine because I'm guessing the expired report is just rebuilt on the fly by the web server.

0
Stef
Telerik team
answered on 24 Mar 2017, 05:19 PM
Hi Stephen,

The Silverlight ReportViewer gets content from the server, that is produced by the Reporting WCF Service. By default the service keeps the produced resources and processing report in memory, where you can configure a physical cache storage to reduce the data kept in memory - Configuring Cache.

The memory for a service hosted in a Web Application will be the ASP.NET Session. When the session ends, or it is cleared, the session state mode is not considered with the hosting environment, the IIS process is interrupted you can lose the session - Report is unavailable or session has expired error message.


About the usage of IsExportEnabled, you can export programmatically reports in the Silverlight application to avoid depending on the viewer - Exporting Report in Silverlight.

In the WPF ReportViewer, the viewer keeps the processed report in memory, and the same processed instance is used on export. Since the memory is different from the web application's one, the report will not expire in the viewer. If you prefer, you can create a backup export option in code - Exporting Report Programmatically.

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
Stephen McDaniel
Top achievements
Rank 1
answered on 24 Mar 2017, 10:23 PM

Thanks for all the help on this issue.  I really appreciate it!

I read about using the file system to cache things but that seemed like a complexity we didn't want to deal with.  We don't really want to pollute the web server with temporary files if we can avoid it.  And it's certainly not a big deal if a report does expire since it probably means the user was working on something else for a while or maybe they just got unlucky and were working during an IIS recycle.  We don't mind if the user gets an "Oops, you waited too long and so you'll need to re-run the report".  However, it was nice in SL that even when that happened, we could let them export the report (which for us is a very common use case).  It's especially useful when re-running the report could take a long time.

I know that there is a programmatic way to export reports but we aren't trying to "avoid depending on the viewer".  The use case I'm talking about is when the user is in the report viewer, clicks to a new page, gets an 'expired' message but then wants to export.  I suppose we could hide the standard export dropdown in the viewer and add our own custom dropdown that doesn't get disabled....but that seems like a lot of custom work and otherwise we really like how the standard export dropdown works.  We'd rather not have to code our own programmatic export UI.

I should explain that our WPF app is maybe a bit different than the normal one.  Since we are porting over our Silverlight code, we are trying to keep the same overall architecture.  That is, our WPF app will still talk to a web server for any time it needs to hit the database.  This is true for just normal data operations elsewhere in our app but also within the reporting module.  In fact, our WPF app won't even be able to talk to the database directly (the database credentials only exist on the web server in a secure way).

The way we have the report viewer coded up in our WPF version of our app is to use the REST service to run reports.  That works well since only the web server can connect to the database.  We also rely on a custom IReportResolver for the SL app with lots of fancy logic for dynamically building up and processing the reports themselves.  The REST service for WPF has worked out really well because we can re-use 99% of that same IReportResolver logic.

While we haven't gotten far enough to verify, I assume that since the WPF app is using the REST service to run the reports, it will have the same issues with reports expiring on the web server.

Hopefully that explains our use case which is probably a bit different than normal.

0
Stef
Telerik team
answered on 29 Mar 2017, 01:42 PM
Hi Stephen,

If you use the WPF ReportViewer with the Reporting REST Service you will not have the issue with the expired session - How To: Use WPF Report Viewer With REST Service.

The Reporting REST Service which will serve content to the client (the WPF application) does not rely on the ASP.NET Session. it has its own cache mechanism that can be configured in the implementation of the ReportsControllerBase, see Storage. The desktop viewer will get a newly created report document each time you want to display a report or to export it.

In your Silverlight application, you can change the Silverlight ReportViewer with an HTML5 ReportViewer that uses the same Reporting REST Service to display reports. In the case of the HTML5 Viewer, the viewer keeps its own id and has sliding expiration that can be set through the Reporting REST Service's ClientSessionTimeout. When the timeout expires there is a message informing the user, and the user can refresh the viewer and to continue working with it.

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
Stephen McDaniel
Top achievements
Rank 1
answered on 28 Apr 2017, 04:28 PM

Thanks for the response.  I've taken that information to my team.  Here are our thoughts:

  • It's nice that the REST service has storage options that aren't just ASP.NET Session....but they all seem very complicated for us.  We'd rather not have to setup file system or database caching.  We don't really have any big problems with session state used for the cache...in fact, we use session state for other things so it is natural for us.
  • We really don't want to switch our SL app to use the HTML5 report viewer.  That seems like a lot of effort and would mean the report viewer's appearance/behavior will change.  Our users don't like change :-)
  • In the end, this is not a huge deal for us.  The only functionality we are losing out on is the ability to export after a report has expired.  If that only works in SL, I guess that will be okay.  We are also considering just resorting to reflection which is probably not what you want to hear :-).

That said, we found another thing that would be nice to have as officially exposed behavior.  In the SL version of our app, we set the ErrorMessage property on the model when we first bring up our window.  Without that, our window is mostly just a big empty gray area where the report would be and users were a bit confused.  Instead, we set the ErrorMessage to something like: "Nothing to display yet, enter some parameters and hit Run to get started".  This way, the user is guided a bit on what their next step is.  In SL, we found the ErrorMessage perfect for this because it display right in the middle of the viewer an automatically goes away when you run a report.

Would there be any way to get a public SetError(string) method on the Report Viewer?

0
Stef
Telerik team
answered on 02 May 2017, 01:27 PM
Hi Stephen,

If you prefer top keep the Silverlight ReportViewer and Reporting WCF service, then check the Session settings in the service's project based on - Report is unavailable or session has expired error message.


About the WPF ReportViewer, if it is not connected to a Reporting REST Service, the viewer will process and render reports with its embedded engine on the current machine. You will have to deliver reports (in DLLs or TRDX|TRDP files) to the client machine, which can be done by your own custom data service.
At the client you can wrap the report depending on its format in a Report Source and pass it to the WPF ReportViewer control.

About the message you want to display, the viewer displays the messages from its TextResources.
You can use the approach from Localization Using the ITextResources interface in order to provide custom messages in the viewer.
You can also throw a custom exception by using the report's Error event, where the message will be displayed in the viewer's page area. The viewer has an Error event as well.

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
Stephen McDaniel
Top achievements
Rank 1
answered on 02 May 2017, 11:52 PM

I understand how to control the session settings.  I'm not so worried about eliminating expired sessions completely.  If a user sits idle on our app for a long time, I'm fine that the session might expire.  My only concern was how the report viewer UI behaved in that case.  But it's a minor thing for us so we can live without it for now.

In our case (as I mentioned above but I know this thread is getting long), we *are* using the REST service.  Our WPF app does not have database credentials (only the web server does) so it's not possible for the viewer to process/render the reports on the current machine.

We've used the TextResources functionality to control other text that the Report Viewer displays.  However, I am talking about showing text when the report viewer is first shown but no report has been run.  In that case, there isn't a TextResources message to configure because there is no message shown in that case with the 'vanilla' report viewer.  Instead, before you run a report it is just a big blank area with a toolbar.  We want to add a new message into that area guiding the user.  So unless I'm missing something, TextResources won't help us here.

I'm not sure how an error event would work for us.  As I mentioned, we are using the REST service so the report viewer isn't really the one in control of the report.  Are you saying we could make some kind of 'dummy' report that is just blank and then cause that dummy report to throw an error?  The whole point of the message we are trying to show is to help the user *before* they've run a report (which for us is time consuming so something we aren't going to do without the user clicking a 'Run' button).

I'm also not sure how an Error event on the viewer helps us.  We can't invoke that error from outside the class....and even if we could, I don't think that would trigger any text to be displayed.

0
Stef
Telerik team
answered on 05 May 2017, 03:04 PM
Hello Stephen,

To have an error handling is OK if you attempt to display a report initially, but you still do not have the user input for report parameters.
If this is not the case, then you can display a blank report with the message on creating the Window. When you have the input for parameters and which report is requested, then you can update the viewer's ReportSource and display the real report.

Another/additional approach will be to let reports be processed on the local machine, but to deliver data from the remote source as in Connecting Telerik Reporting to OData feeds.

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
Tags
General Discussions
Asked by
Stephen McDaniel
Top achievements
Rank 1
Answers by
Stef
Telerik team
Stephen McDaniel
Top achievements
Rank 1
Share this question
or