Silverlight Client using WCF to Sql Reporting Services = NotFound
I am using a Silverlight client with a WCF service reference to a sql 2008 reporting server via the ReportExecution2005.asmx endpoint. I am able to successfully call the LoadReport/LoadReport2 method and receive back a collection of report parameters and an execution id. However, when I call SetExecutionParameters/SetExecutionParameters2 I get the wonderful exception "The remote server returned an error: NotFound.". I have double-checked all parameter values and they appear correct. I have tried including the executionID in an ExecutionHeader class that is added to the OperationContext.Current.OutgoingMessageProperties, and I have tried the OutgoingMessageHeaders as well; but I always get the same NotFound error. Has anyone been able to call the sql reporting services ReportExecution2005 SetExecutionParameters/2 method from a WCF Silverlight client? On a side rant: Is there a reason that the executionID is passed via the SOAP headers rather than as a standard parameter? -parx
March 19th, 2010 10:18pm

Hi parx, From the error message "The remote server returned an error: NotFound", it seems the cause is the Reporting Services does not find the parameters we posted. The parameters are case-sensitive. So, please make sure the parameters are correct. For your reference, below is a code snippet: WSReportExecution2005.ReportExecutionServiceSoapClient rs = new SilverlightApplication1.Web.WSReportExecution2005.ReportExecutionServiceSoapClient(); rs.ClientCredentials.Windows.AllowNtlm = true; rs.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation; // Render arguments byte[] result = null; string reportPath = "/AdventureWorks 2008 Sample Reports/Employee Sales Summary 2008"; string format = "MHTML"; string historyID = null; string devInfo = @"<DeviceInfo><Toolbar>False</Toolbar></DeviceInfo>"; // Prepare report parameter. ParameterValue[] parameters = new ParameterValue[4]; parameters[0] = new ParameterValue(); parameters[0].Name = "EmployeeID"; parameters[0].Value = "283"; parameters[1] = new ParameterValue(); parameters[1].Name = "ReportMonth"; parameters[1].Value = "6"; // June parameters[2] = new ParameterValue(); parameters[2].Name = "ReportYear"; parameters[2].Value = "2003"; parameters[3] = new ParameterValue(); parameters[3].Name = "ShowDescription"; parameters[3].Value = "false"; DataSourceCredentials[] credentials = null; string showHideToggle = null; string encoding; string mimeType; string extension; Warning[] warnings = null; ParameterValue[] reportHistoryParameters = null; string[] streamIDs = null; ExecutionInfo2 execInfo2 = new ExecutionInfo2(); ExecutionHeader execHeader = new ExecutionHeader(); ServerInfoHeader svrinfoHeader; execHeader = rs.LoadReport2(null, reportPath, historyID, out svrinfoHeader, out execInfo2); rs.SetExecutionParameters2(execHeader, null, parameters, "en-us", out execInfo2); String SessionId = execInfo2.ExecutionID.ToString(); try { rs.Render(execHeader, null, format, devInfo, out result, out extension, out mimeType, out encoding, out warnings, out streamIDs); } catch (Exception exp) { //Print the error message. } By the way, we can find the root cause from SQL Server Reporting Services logs. By default, the logs are located on:C:\Program Files\Microsoft SQL Server\MSRS10.MSSQLSERVER\Reporting Services\LogFiles If you have any more questions, please feel free to ask. Thanks,Jin Chen Jin Chen - MSFT
Free Windows Admin Tool Kit Click here and download it now
March 22nd, 2010 8:04am

I am having difficulty compiling your sample code inside of a Silverlight application (to clarify, Silverlight version 3). The code looks very similar to how one would access SOAP via an ASMX code behind page. There are several properties that do not exist in my Silverlight project; for example, ClientCredentials.Windows property and System.Security.Principal.TokenImpersonationLevel. And the proxy calls have different signatures from the Service Reference generated code I have. Additionally, all proxy calls must be async in Silverlight, but I do not see that in your sample code. However, the location of the SSRS logs was very helpful. Thank you! From one of the error entries, I can see that the session identifier (I assume the ExecutionHeader.ExecutionId) is not being sent correctly by the client: library!ReportServer_0-11!584!03/22/2010-09:25:07:: e ERROR: Throwing Microsoft.ReportingServices.Diagnostics.Utilities.MissingSessionIdException: The session identifier is missing. A session identifier is required for this operation. , ; Info: Microsoft.ReportingServices.Diagnostics.Utilities.MissingSessionIdException: The session identifier is missing. A session identifier is required for this operation. Given this information, I again focused my attention on the soap header portion. Using Fiddler, I compared an ASMX SOAP call with the Silverlight WCF call.ASMX SOAP output: <soap:Header><ExecutionHeader xmlns="http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices"><ExecutionID>x1igj445lk4qem55elspdg55</ExecutionID></ExecutionHeader></soap:Header>Original WCF output: <s:Header><ExecutionHeader xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices"><ExecutionID xmlns="http://schemas.datacontract.org/2004/07/MyCompany.SSRS.ReportExecutionProxy">jiltpd55ajw2oq45ltnglb45</ExecutionID></ExecutionHeader></s:Header> The ExecutionID element is getting an auto-generated namespace of "http://schemas.datacontract.org/2004/07/MyCompany.SSRS.ReportExecutionProxy". I am not sure where this is coming from, but a few tweaks of the auto-generated Reference.cs file resolved the problem. For the ExecutionHeader class, I added [System.Runtime.Serialization.DataContract(Namespace="http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices")], and for the property ExecutionID, I added [System.Runtime.Serialization.DataMember(Order = 0)]. Both of these attributes force the serializer to generate the correct SOAP header. Note that I have mucked around with an auto-generated file, beware... Updated WCF output: <s:Header><ExecutionHeader xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices"><ExecutionID>oyyr0r45nsxzg345jkr05ijp</ExecutionID></ExecutionHeader></s:Header> For completeness, here is sample code for calling the SetExecutionParameter2 method. Note that I am using a callback delegate for the optional userState - your usage may vary. public void SetReportParameters(string executionID, IEnumerable<ParameterValue> parameterValues, Action<Exception> callback) { if (_reportExecutionProxyClient != null) { using (OperationContextScope context = SetExecutionHeader(executionID)) { ParameterValue[] parameterValuesArray = parameterValues.ToArray(); string parameterLanguage = System.Threading.Thread.CurrentThread.CurrentUICulture.Name; _reportExecutionProxyClient.SetExecutionParameters2Async(parameterValuesArray, parameterLanguage, callback); } } } private OperationContextScope SetExecutionHeader(string executionID) { OperationContextScope context = new OperationContextScope(_reportExecutionProxyClient.InnerChannel); ExecutionHeader executionHeaderData = new ExecutionHeader() { ExecutionID = executionID, }; string headerName = "ExecutionHeader"; #if true // add the ExecutionHeader entry to the soap headers string headerNamespace = "http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices"; MessageHeader executionHeader = MessageHeader.CreateHeader(headerName, headerNamespace, executionHeaderData); OperationContext.Current.OutgoingMessageHeaders.Add(executionHeader); #else // this does not appear to affect the soap headers OperationContext.Current.OutgoingMessageProperties.Add(headerName, executionHeaderData); #endif return context; } There are hard-coded strings, and mucking around with the auto-generated Reference.cs gives me the hebegebees. I am sure there is a "better" way that someone will suggest. -parx
March 22nd, 2010 7:14pm

Partial classes to the rescue. ExecutionHeader is specified as a partial class in the auto-generated Reference.cs file. This allows the functionality to be easily extended without modifying the Reference.cs file itself. I created ReportExecutionProxyExtensions.cs and insured that the namespace matches that used in the service proxy Reference.cs file: using System; using System.Runtime.Serialization; using System.ServiceModel.Channels; namespace Microsoft.SqlServer.ReportingServices.ReportExecutionProxy { /// <summary> /// Functionality added to the Microsoft Sql Server Reporting Services /// service reference to force the ExecutionHeader class to correctly /// serialize the execution id into a soap header via wcf. /// </summary> [DataContract(Namespace = "http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices")] public partial class ExecutionHeader { /// <summary> /// The local name of the header xml element. /// </summary> public static readonly string HeaderName = "ExecutionHeader"; /// <summary> /// The namespace uri of the header xml element. /// </summary> public static readonly string HeaderNamespace = "http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices"; /// <summary> /// Gets or sets the execution id for the ExecutionHeader class. /// This dummy property forces the correct serialization of the ExecutionID /// field into the soap header. /// </summary> [DataMember(Order = 0, Name="ExecutionID")] public string ExecutionIDForWcfSoapHeader { get { return this.executionIDField; } set { this.executionIDField = value; } } /// <summary> /// Creates a message header containing the ExecutionHeader suitable for /// inclusion in a soap header. /// </summary> /// <returns>A MessageHeader representing the execution context.</returns> public MessageHeader CreateMessageHeader() { MessageHeader executionHeader = MessageHeader.CreateHeader(HeaderName, HeaderNamespace, this); return executionHeader; } } } Now the service reference can be generated and updated without worry of overwriting manual code changes and the proxy class usage can be simplified to the following: private OperationContextScope SetMessageHeaders(string executionID) { OperationContextScope context = new OperationContextScope(_reportExecutionProxyClient.InnerChannel); ExecutionHeader executionHeaderData = new ExecutionHeader() { ExecutionID = executionID, }; #if true // add the ExecutionHeader entry to the soap headers OperationContext.Current.OutgoingMessageHeaders.Add(executionHeaderData.CreateMessageHeader()); #else // this does not appear to affect the soap headers OperationContext.Current.OutgoingMessageProperties.Add(ExecutionHeader.HeaderName, executionHeaderData); #endif return context; } -parx
Free Windows Admin Tool Kit Click here and download it now
March 23rd, 2010 12:33pm

How can i solve following issue in Silverlight Client using WCF to SqlReporting Services? Microsoft.ReportingServices.Diagnostics.Utilities.MissingSessionIdException: The session identifier is missing. A session identifier is required for this operation. , ; Info: Microsoft.ReportingServices.Diagnostics.Utilities.MissingSessionIdException: The session identifier is missing. A session identifier is required for this operation.
December 7th, 2010 5:55am

I ran into the same issue recently as well. There is very little documentation on the Async methods and how to keep the ExecutionID alive between the calls. I have to applaud the partial class and the heads up on the hint on the Session Identifier not being passed. It took this article along with -> http://msdn.microsoft.com/en-us/library/ms155081.aspx to get me to understand what is going on. My project was using Silverlight to call the SQL Reporting Services web service. I ran the above public void SetReportParameters(string executionID, IEnumerable<ParameterValue> parameterValues, Action<Exception> callback) { if (_reportExecutionProxyClient != null) { using (OperationContextScope context = SetExecutionHeader(executionID)) { ParameterValue[] parameterValuesArray = parameterValues.ToArray(); string parameterLanguage = System.Threading.Thread.CurrentThread.CurrentUICulture.Name; _reportExecutionProxyClient.SetExecutionParameters2Async(parameterValuesArray, parameterLanguage, callback); } } } but I had to chain each async call together and include the using(OperationContextScope = SetExecutionHeader(ExecutionID)) around every Completed & Async method, making sure I passed the ExecutionID gathered from the server on the Initial LoadAsync() method. Once I had the ExecutionID from the server, I used this to populate the ExecutionID & ExecutionIDForWcfSoapHeader of the OperationScope. The only change I had to make, and it wouldn't work for me, unless I did it, was include the ExecutionIDForWCFSoapHeader in the setting of the executionHeaderData object in the SetMessagHeaders function here is a code sample below: (I tired to use the code formatter, but it just made it into one line) //Main Call public void GetReportByReportLocation(string reportLocation, Action<Report, Exception> completed) { parameterValues = new ParameterValue[0]; execInfo = new ExecutionInfo(); execHeader = new ExecutionHeader(); //1. Load and get Parameters - 1st in chain reportClient.LoadReportCompleted += reportClient_LoadReportCompleted; reportClient.LoadReportAsync(reportLocation, null, completed); } void reportClient_LoadReportCompleted(object sender, LoadReportCompletedEventArgs e) { var result = e.Result; var callback = e.UserState as Action<Report, Exception>; execHeader.ExecutionID = result.ExecutionID; execInfo = result; execInfo.ExecutionID = result.ExecutionID; SetReportParameters(execHeader.ExecutionID, new ParameterValue[0], callback); } void reportClient_SetExecutionParametersCompleted(object sender, SetExecutionParametersCompletedEventArgs e) { var callback = e.UserState as Action<Report, Exception>; SetRenderAsync(execHeader.ExecutionID, format,null, callback); } public void SetRenderAsync(string executionID, string format, string deviceInfo, Action<Report, Exception>callback ) { if (reportClient != null) { using (OperationContextScope context = SetMessageHeaders(executionID)) { reportClient.RenderCompleted += new EventHandler<RenderCompletedEventArgs>(reportClient_RenderCompleted); reportClient.RenderAsync(format, null, callback); } } } public void SetReportParameters(string executionID, IEnumerable<ParameterValue> parameterValues, Action<Report, Exception> callback) { if (reportClient != null) { using (OperationContextScope context = SetMessageHeaders(executionID)) { ParameterValue[] parameterValuesArray = parameterValues.ToArray(); string parameterLanguage = System.Threading.Thread.CurrentThread.CurrentUICulture.Name; reportClient.SetExecutionParametersCompleted += new EventHandler<SetExecutionParametersCompletedEventArgs>(reportClient_SetExecutionParametersCompleted); reportClient.SetExecutionParametersAsync(parameterValuesArray, parameterLanguage, callback); } } } void reportClient_RenderCompleted(object sender, RenderCompletedEventArgs e) { var result = e.Result; var callback = e.UserState as Action<Report, Exception>; var memoryStream = new MemoryStream(result); memoryStream.Seek(0, SeekOrigin.Begin); var report = new Report() { Bytes = e.Result, Type = e.MimeType }; callback(report, null); } //Helper Functions private OperationContextScope SetMessageHeaders(string executionID) { OperationContextScope context = new OperationContextScope(reportClient.InnerChannel); ExecutionHeader executionHeaderData = new ExecutionHeader() { ExecutionID = executionID, ExecutionIDForWcfSoapHeader = executionID }; #if true // add the ExecutionHeader entry to the soap headers OperationContext.Current.OutgoingMessageHeaders.Add(executionHeaderData.CreateMessageHeader()); #else // this does not appear to affect the soap headers OperationContext.Current.OutgoingMessageProperties.Add(ExecutionHeader.HeaderName, executionHeaderData); #endif return context; } Hope this helps somebody and helps with the Async Silverlight Madness! Ron
Free Windows Admin Tool Kit Click here and download it now
July 14th, 2012 2:46pm

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics