I recently experienced problems when trying to view a report for SQL Server Reporting Services with ReportViewer for MVC.
The report worked in some cases, but failed when certain parameters were set.
Exception and stack trace:
[ReportServerException: The report parameter 'DeviceTypes' is read-only and cannot be modified. (rsReadOnlyReportParameter)] Microsoft.Reporting.WebForms.ServerReportSoapProxy.OnSoapException(SoapException e) +155 Microsoft.Reporting.WebForms.Internal.Soap.ReportingServices2005.Execution.ProxyMethodInvocation.Execute(RSExecutionConnection connection, ProxyMethod`1 initialMethod, ProxyMethod`1 retryMethod) +1256 Microsoft.Reporting.WebForms.Internal.Soap.ReportingServices2005.Execution.RSExecutionConnection.SetExecutionParameters(ParameterValue[] Parameters, String ParameterLanguage) +370 Microsoft.Reporting.WebForms.SoapReportExecutionService.SetExecutionParameters(IEnumerable`1 parameters, String parameterLanguage) +530 Microsoft.Reporting.WebForms.ServerReport.SetParameters(IEnumerable`1 parameters) +896 Microsoft.Reporting.WebForms.Report.SetParameters(ReportParameter parameter) +136 ReportViewerForMvc.ReportExtensions.SetParameters(Report report, ReportParameterInfoCollection collection) +114 ReportViewerForMvc.ReportViewerExtensions.SetProperties(ServerReport serverReport, ServerReport properties) +84 ReportViewerForMvc.ReportViewerExtensions.SetProperties(ReportViewer reportViewer, ReportViewer properties) +117 ReportViewerForMvc.ReportViewerWebForm.BuildReportViewer() +92 System.Web.UI.Control.OnLoad(EventArgs e) +109 System.Web.UI.Control.LoadRecursive() +68 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +4498
Checked the ReportServerService__*.log and ExecutionLog* database views, but they contained no additional clues about the error.
I attached WinDbg (x64) to the IIS worker process (w3wp.exe) and set a breakpoint with:
!bpmd ReportViewerForMvc.dll ReportViewerForMvc.ReportExtensions.SetParameters
Messages from WinDbg:
Found 2 methods in module 00007ff9bde79bb0... MethodDesc = 00007ff9c00a30d0 MethodDesc = 00007ff9c00a30e0 Setting breakpoint: bp 00007FF9C0EE5590 [ReportViewerForMvc.ReportExtensions.SetParameters(Microsoft.Reporting.WebForms.Report, Microsoft.Reporting.WebForms.ReportParameterInfo)] Setting breakpoint: bp 00007FF9C0EE53E4 [ReportViewerForMvc.ReportExtensions.SetParameters(Microsoft.Reporting.WebForms.Report, Microsoft.Reporting.WebForms.ReportParameterInfoCollection)] Adding pending breakpoints...
Continued exection, reloaded the report and the breakpoint was hit.
Checked the .NET call stack with:
!clrstack -a
Part of the result:
OS Thread Id: 0x273c (45) Child SP IP Call Site 00000007dba9d030 00007ff9c0ee53e4 ReportViewerForMvc.ReportExtensions.SetParameters(Microsoft.Reporting.WebForms.Report, Microsoft.Reporting.WebForms.ReportParameterInfoCollection) PARAMETERS: report (<CLR reg>) = 0x0000000390e93650 collection (<CLR reg>) = 0x0000000490886678
Examined the collection object with:
!DumpObj /d 0000000490886678
Result:
Name: Microsoft.Reporting.WebForms.ReportParameterInfoCollection MethodTable: 00007ff9bff1cc98 EEClass: 00007ff9bff08d40 Size: 32(0x20) bytes File: C:\Windows\assembly\GAC_MSIL\Microsoft.ReportViewer.WebForms\11.0.0.0__89845dcd8080cc91\Microsoft.ReportViewer.WebForms.dll Fields: MT Field Offset Type VT Attr Value Name 00007ffa1b23d408 40017fa 8 ...Canon, mscorlib]] 0 instance 00000004908823f0 list 00007ffa1b8de068 40017fb 10 System.Object 0 instance 0000000000000000 _syncRoot
Examined the list array with:
!DumpArray /d 00000004908823f0
Result:
Name: Microsoft.Reporting.WebForms.ReportParameterInfo[] MethodTable: 00007ff9c0fd9e60 EEClass: 00007ffa1b2f0f10 Size: 120(0x78) bytes Array: Rank 1, Number of elements 12, Type CLASS Element Methodtable: 00007ff9bff1cbc0 [0] 00000004908826c8 [1] 00000004908829d8 [2] 0000000490882ce8 [3] 00000004908832e0 [4] 0000000490884490 [5] 00000004908847a8 [6] 0000000490884ac0 [7] 0000000490884e38 [8] 00000004908853f8 [9] 0000000490885818 [10] 0000000490886250 [11] 00000004908865c8
Examined details for the list array with:
!DumpArray /d -details 00000004908823f0
Part of the result:
[11] 00000004908865c8 Name: Microsoft.Reporting.WebForms.ReportParameterInfo MethodTable: 00007ff9bff1cbc0 EEClass: 00007ff9bff08cc8 Size: 104(0x68) bytes File: C:\Windows\assembly\GAC_MSIL\Microsoft.ReportViewer.WebForms\11.0.0.0__89845dcd8080cc91\Microsoft.ReportViewer.WebForms.dll Fields: MT Field Offset Type VT Attr Value Name 00007ffa1b8dda88 4000120 8 System.String 0 instance 0000000490881950 m_name 00007ff9bff1c678 4000121 50 System.Int32 1 instance 4 m_dataType 00007ffa1b8cd6f8 4000122 58 System.Boolean 1 instance 0 m_isNullable 00007ffa1b8cd6f8 4000123 59 System.Boolean 1 instance 1 m_allowBlank 00007ffa1b8cd6f8 4000124 5a System.Boolean 1 instance 1 m_isMultiValue 00007ffa1b8cd6f8 4000125 5b System.Boolean 1 instance 1 m_isQueryParameter 00007ffa1b8dda88 4000126 10 System.String 0 instance 000000038e411420 m_prompt 00007ffa1b8cd6f8 4000127 5c System.Boolean 1 instance 0 m_promptUser 00007ffa1b8cd6f8 4000128 5d System.Boolean 1 instance 1 m_areDefaultValuesQueryBased 00007ffa1b8cd6f8 4000129 5e System.Boolean 1 instance 1 m_areValidValuesQueryBased 00007ffa1b8dda88 400012a 18 System.String 0 instance 0000000000000000 m_errorMessage 00007ff9c0fda240 400012b 20 ...Viewer.WebForms]] 0 instance 0000000490886320 m_validValues 00007ffa1b23d128 400012c 28 ...tring, mscorlib]] 0 instance 0000000490886658 m_currentValues 00007ff9bff1c7c8 400012d 54 System.Int32 1 instance 0 m_state 00007ff9bff1cc98 400012e 30 ...terInfoCollection 0 instance 0000000490886fb8 m_dependencyCollection 00007ff9bff1cc98 400012f 38 ...terInfoCollection 0 instance 0000000000000000 m_dependentsCollection 00007ffa1b8c1480 4000130 40 System.String[] 0 instance 0000000490881bb8 m_dependencies 00007ff9c0fda5d0 4000131 48 ...Viewer.WebForms]] 0 instance 0000000490886630 m_dependentsCollectionConstruction 00007ffa1b8cd6f8 4000132 5f System.Boolean 1 instance 1 m_visible
Examined the name of the last report parameter with:
!DumpObj /d 0000000490881950
Part of the result:
Name: System.String MethodTable: 00007ffa1b8dda88 EEClass: 00007ffa1b236a08 Size: 48(0x30) bytes File: C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll String: DeviceTypes
So the last parameter was DeviceTypes, the one causing the problem.
Looked for a read-only property among the report parameters. Noticed that m_promptUser was 0 for the DeviceTypes parameter, while m_promptUser was 1 for all other parameters.
I decided to use procdump to log exception messages from the ReportingServicesService.exe process with:
procdump.exe -f "" -l -e 1 ReportingServicesService.exe
Reloaded the report to recreate the error.
Part of the result was:
[07:10:37] Exception: E0434F4D.Microsoft.ReportingServices.Diagnostics.Utilities.ReadOnlyReportParameterException ("The report parameter 'DeviceTypes' is read-only and cannot be modified.") [07:10:37] Exception: E0434F4D.Microsoft.ReportingServices.Diagnostics.Utilities.RSException ("The report parameter 'DeviceTypes' is read-only and cannot be modified.")
Then loaded all DLL files from SSRS into ILSpy from:
C:\Program Files\Microsoft SQL Server\MSRS11.MSSQLSERVER\Reporting Services\ReportServer\bin
Searched for the ReadOnlyReportParameterException class in ILSpy.
Found it and noticed that it was apparently only used by:
Microsoft.ReportingServices.ReportProcessing.ParameterInfoCollection.Combine(...)
Read the decompiled code for the above method and noticed this part:
if (checkReadOnly && !parameterInfo.PromptUser) { ParameterInfoCollection.ThrowReadOnlyParameterException(parameterInfo.Name, isSharedDataSetParameter); }
Apparently the value of parameterInfo.PromptUser determined the read-only status.
I decided to examine the XML for the RDL report and noticed that the DeviceTypes report parameter did not have a Prompt section.
I added this:
<Prompt>DeviceTypes</Prompt>
Then uploaded the new version of the report (by overwriting).
However this did not seem to have any immediate effect, the error still occured…
I spent some time examining various other ideas and internals of SSRS.
Then I got an idea: I decided to delete the problematic report and then recreate the modified version with a Prompt section.
This fixed the problem! The report now worked in all cases, no matter which parameters were set.
This behavior was consistent across 2 SSRS instances.
Conclusion
It seems that read-only status for a report parameter is derived from the presence of a <Prompt>Description</Prompt> section.
However this status is not updated if the report is overwritten, it has to be deleted and then recreated…
Due to the way ReportViewerForMvc.dll is implemented all report parameters are copied from the initial instance to another instance of ReportViewer.
This means that report parameters can’t be read-only, so <Prompt>Description</Prompt> should always be specified for all report parameters, when using ReportViewer for MVC.