Click here to Skip to main content
15,885,757 members
Articles / Web Development / ASP.NET

A reporting service using SOAP calls passing XML to a Data Extension

Rate me:
Please Sign up or sign in to vote.
4.00/5 (5 votes)
19 Oct 2005CPOL8 min read 85.4K   406   26  
Demostrates how to render a report by passing XML to a data extension via SOAP calls.
/*=====================================================================
  File:     ReportViewer.cs

  Summary:  Main class for the Microsoft SQL Server Reporting Services sample
                  server control.

---------------------------------------------------------------------


=====================================================================*/
#region Disclaimer by Teo Lachev "Microsoft Reporting Services in Action"
/*============================================================================
  File:     RsReportViewer.cs

  Summary:  An enhanced version of the ReportViewer sample control
--------------------------------------------------------------------
  This code sample was built upon on the Microsoft's ReportViewer control included 
  with the RS samples.
 
  The following portions of the code have been changed/added to fit the book needs:
  1. Supports server-side report generation.
  2. Supports ICustomTypeDescriptor
    
===========================================================================*/
#endregion

using System;
using System.ComponentModel;
using System.Collections;
using System.Collections.Specialized;

using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing.Design;
using System.Drawing;

// my namespaces
using RsReportViewer.RS;
using System.Text;
using System.Web;
using System.Web.Services.Protocols;
using System.IO;
using System.Diagnostics;
using System.Xml;
using System.Data;
using System.Net;

namespace RSControl.WebViewer
{
	public class RSReportViewer : WebControl, ICustomTypeDescriptor
	{
		#region Private Member Variables
		// Private members that will map to url access builder.
		private multiState _showToolbar = 0;
		private multiState _parameters = 0;
		private string _zoom = "100%";   
		private string _searchstring = String.Empty;
		private string _searchnextstring = String.Empty;
		private string _reportParameters = String.Empty;
		private string _addFilter = String.Empty;
		private string _filterValues = String.Empty;
		private string _serverUrl = "";
		private string _url = String.Empty;
		private String _reportPath = "";
		private string _renderingFormat = "Default";
		private Hashtable _properties = new Hashtable();

		// my properties
		private multiState		_serverSide = 0;							// client-side or server-side report generation
		private HybridDictionary	_parameterValues = new HybridDictionary();	// report request
		private string			_streamRoot = "http://localhost/RSTestApp/ImageHandler.aspx?ID=";
		private string			_imageDownloadPath =@"temp";

		#endregion
      
		#region Public Enums for Property Browser
		public enum multiState {Default, True, False};
		#endregion
      
		#region Enum to String Conversion Arrays
		private string[] multiStateArray = {null, "true", "false"};      
		#endregion

		#region Constructors
		public RSReportViewer()
		{
			
		}
      
		#endregion

		#region Propertes
		[Browsable(true), ReadOnly(true),
		Category("General Report Parameters"),
		Description("Full report url.")]
		public string Url
		{
			get
			{
				return this._url;
			}
		}
      
		[Category("General Report Parameters"),
		Editor(typeof(StringEditor), typeof(UITypeEditor)),
		Description("Server url such as http://localhost/reportserver")]
		public string ServerUrl
		{
			get
			{
				return this._serverUrl;
			}
			set
			{
				this._serverUrl = value;
				// Build the full url string when the property is set. 
				this.BuildUrlString();
		    
			}
		}
      
		[Category("General Report Parameters"),
		Description("Report path such as /SampleReports/Company Sales")]
		public String ReportPath
		{
			get
			{
				return this._reportPath;
			}

			set
			{
				this._reportPath = value;
				// Build the full url string when the property is set.
				this.BuildUrlString();
			}
		}



		[Category("HTMLViewer Commands"),
		Description("Indicates whether to display the report toolbar.")]
		public multiState ToolbarVisible
		{
			get
			{
				return this._showToolbar;
			}
			set
			{
				this._showToolbar = value;
				this.SetParameter("rc:toolbar", multiStateArray[(int)value]);
			}
		}
      
		[Category("HTMLViewer Commands"),
		Description("Indicates whether to show the parameters area of the toolbar.")]
		public multiState ParametersVisible
		{
			get
			{
				return this._parameters;
			}
			set
			{
				this._parameters = value;
				this.SetParameter("rc:parameters", multiStateArray[(int)value]);
			}
		}

		[Category("HTMLViewer Commands"),
		Description("Sets the zoom property of the report"),
		Editor(typeof(ZoomListboxTypeEditor), typeof(UITypeEditor))
		]
		public string Zoom
		{
			get
			{
				return this._zoom;
			}
			set
			{
				this._zoom = value;
				this.SetParameter("rc:zoom", value);
			}
		}
      
		[Category("Rendering Format"),
		Editor(typeof(FormatListboxTypeEditor), typeof(UITypeEditor)),
		Description("Sets the report rendering format.")
		]
		public string Format
		{
			get
			{
				return this._renderingFormat.ToLower()=="default"?"HTML4.0":this._renderingFormat;
			}

			set
			{
				this._renderingFormat = value;
				this.SetParameter("rs:Format", value);
			}
		}

       #endregion

	  #region My Properties
	   [Category("Server-side Execution Options"),
	   Description("Indicates whether to generate the report on the server-side.")]
	   public multiState ServerSide
	   {
		   get
		   {
			   return this._serverSide;
		   }
		   set
		   {
			   this._serverSide = value;
		   }
	   }

	   [Category("Server-side Execution Options"),
	   Description("The absolute URL to the server-side image handler page to render images with HTML reports. Corresponds to the StreamRoot device setting. If left blank, defaults to the ImageDownloadPath.")]
	   public string StreamRoot
	   {
		   get
		   {
			   return this._streamRoot;
		   }
		   set
		   {
			   this._streamRoot = value;
		   }
	   }

	   [Category("Server-side Execution Options"),
	   Description("The relative to the the application virtual root folder where the images will be saved for HTML reports.")]
	   public string ImageDownloadPath
	   {
		   get
		   {
			   return this._imageDownloadPath;
		   }
		   set
		   {
			   this._imageDownloadPath = value;
		   }
	   }


	   public void AddParameter (string name, string value)
	   {
			_parameterValues.Add(name, value);
	   }

	   [Browsable(true), ReadOnly(true),
	   Category("Server-side Execution Options"),
	   Description("Set this to an instance of a .NET dataset during runtime for reports which use the Custom Dataset Extension. If you set this property, the ReportViewer will add a DataSource parameter for you in the Report Parameters collection.")]
	   public System.Data.DataSet DataSource 
	   {

		   get
		   {
				return null;
		   }
		   set
		   {
			   // if the dataset parameter is set during runtime
			   // add DataSource parameter to the parameter collection
			   if (_parameterValues["DataSource"]!=null) _parameterValues.Remove("DataSource");
			   StringBuilder stringBuilder = new StringBuilder();
			   StringWriter stringWriter = new StringWriter(stringBuilder);
			   value.WriteXml(stringWriter, XmlWriteMode.WriteSchema);
			   _parameterValues.Add("DataSource", stringBuilder.ToString());
			   stringWriter.Close();

		   }
		   
	   }

	   /// <summary>
	   /// Determines whether the report is HTML-based
	   /// </summary>
	   /// <param name="reportFormat">The Report format</param>
	   /// <returns>true, if the report is requested in HTML</returns>
	   private bool IsHtmlReport
	   {
		   get 
		   {
			   return ("ht" == this.Format.Substring(0, 2).ToLower());
		   }
	   }
	   #endregion
      
      #region Methods
      /// <summary>
      /// Add or remove url access string properties. 
      /// </summary>
      /// <param name="name"></param>
      /// <param name="value"></param>
      private void SetParameter(string name, string value)
      {
         try
         {
            // Remove if value is null or empty. Value is null of the property grid value
            // is null or empty. Empty or null removes the property from the Hashtable.
            if(value == null | value == String.Empty )
            {
               this._properties.Remove(name);
            }
            else
            {
               if(this._properties.ContainsKey(name))
               {
                  // Change if key exists
                  this._properties[name] = value;
               }
               else
               {
                  // Add if key does not exist
                  this._properties.Add(name, value);
               }
            }
            // Build a new url string
            this.BuildUrlString();
         }
            // Catch and handle a more specific exception in a propduction application.
         catch(Exception ex)
         {
            // Sample throws the exception to the client
            throw ex;
         }
      }
      
      /// <summary>
      /// Enumerate Hashtable and create report server access specific string.
      /// </summary>
      /// <param name="properties"></param>
      /// <returns></returns>
      private string EmumProperties(Hashtable properties)
      {
         string paramsString = String.Empty;
         // Enumerate properties and create report server specific string.
         IDictionaryEnumerator customPropEnumerator = properties.GetEnumerator();
         while ( customPropEnumerator.MoveNext() )
         {
            paramsString += "&" 
               + customPropEnumerator.Key 
               + "=" + customPropEnumerator.Value;
         }

         return paramsString;
      }
      
      /// <summary>
      /// Add URL access command for rendering a report and any
      /// additional parameters.
      /// </summary>
      public string BuildUrlString()
      {
		  this._url = this._serverUrl + "?" + this._reportPath + 
			  "&rs:Command=Render" + this.EmumProperties(this._properties);
		  return this._url;
      }
      #endregion


      #region Render
      /// <summary>
      /// Render the report on the client or server-side
      /// </summary>
      /// <param name="output"></param>
      protected override void Render(HtmlTextWriter output)
      {
         if (this._serverUrl == String.Empty || this._reportPath == String.Empty)
         {
            output.Write(MessageToHTML("To render a report, enter the ServerUrl and ReportPath."));
			return;
         }
		  if (this.ServerSide == multiState.True && System.Web.HttpContext.Current == null)
		  {
			  // running in design mode
			  return;
		  }

		  if (this.ServerSide != multiState.True)
		  {
			  // Client-side generation is the same as with the Report Viewer control
			  // Create IFrame if the user enters ServerUrl and ReportPath
			  output.WriteBeginTag("iframe");

			  output.WriteAttribute("src", this.BuildUrlString());
			  output.WriteAttribute("width", this.Width.ToString());
			  output.WriteAttribute("height", this.Height.ToString());
			  output.WriteAttribute("style", "border: 1 solid #C0C0C0");
			  output.WriteAttribute("border", "0");
			  output.WriteAttribute("frameborder", "0");

			  output.Write(HtmlTextWriter.TagRightChar);
			  output.WriteEndTag("iframe");
			  output.WriteLine();
		  }
		  else
		  { 
			  // Server-side generation
			  try	
			  {
				  // Render the report via SOAP
				  byte[] result = RenderReport();

				  // render the report as HTMLFragment for html reports
				  if (this.IsHtmlReport)
				  {
					  // this an html report
					  // so just stream it back as fragment
					  string res = ASCIIEncoding.ASCII.GetString(result);
					  output.Write(res);
				  }
				  else
				  {
					  // some other export format was requested
					  // stream the payload in binary format
					  HttpResponse response = System.Web.HttpContext.Current.Response;
//					  response.ClearContent();
//					  response.ClearHeaders();
					  string fileName = GetFileName(this.ReportPath, this.Format);
					  response.ContentType = GetContentType(Path.GetExtension(fileName));
					  response.AddHeader ("content-disposition", "attachment; filename=\"" + fileName + "\"");
//					  response.BinaryWrite(result);
//					  response.Flush();
//					  response.Close();
					  response.BinaryWrite(result);
				  }
			  }
			  catch (SoapException ex)
			  {
				  output.Write(MessageToHTML(ex.Detail.OuterXml));
			  }
			  catch (System.Exception ex)
			  {
				  output.Write(MessageToHTML(ex.ToString()));
			  }
			  
		  }
      }


      #endregion

	  #region My methods
	
	/// <summary>
	/// Renders the report via SOAP
	/// </summary>
	/// <returns></returns>
	   private byte[] RenderReport()
	   {
			ReportingService rs = new ReportingService();
			rs.Url = this._serverUrl;
			rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
      
		   // Render arguments
		   byte[] result = null;
		   string reportPath = this.ReportPath;
		   string historyID = null;
		   string format = this.Format;
		   string devInfo = null;	// not supported for now
		   DataSourceCredentials[] credentials = null;
		   string showHideToggle = null;
		   string encoding;
		   string mimeType;
		   Warning[] warnings = null;
		   ParameterValue[] reportHistoryParameters = null;
		   string[] streamIDs = null;
		   ParameterValue[] reportParameters = null;
		   string optionalString = null;
		   string imageDownloadPath = null; 
		   SessionHeader sh = new SessionHeader();

		   // set the report parameters
		   if (_parameterValues.Count>0)
		   {
				reportParameters = new ParameterValue[_parameterValues.Count];
				
				int i = 0;
				foreach (DictionaryEntry parameter in _parameterValues )
				{
					reportParameters[i] = new ParameterValue();
					reportParameters[i].Name = parameter.Key.ToString();
					reportParameters[i].Value = parameter.Value.ToString();
					i++;
				}
		   }

		   try
		   {
			   // set the streamrootpath so the Report Server can save the images to this folder
			   if (System.Web.HttpContext.Current != null)
			   {
				   imageDownloadPath = System.Web.HttpContext.Current.Request.PhysicalApplicationPath + 
					   this.ImageDownloadPath + Path.DirectorySeparatorChar;
			   }

			   // if ImageDownloadPath is not specified, default to the StreamRoot path
			   // NOTE: Defaulting to StreamRoot will not work for Internet reports
			   // Please refer to Chapter 11 for a detailed discussion.
			   devInfo = AddDeviceSetting("StreamRoot", (this.StreamRoot==String.Empty) ? imageDownloadPath:this.StreamRoot, devInfo);


			   // render the report as HTMLFragment for html reports
			   if (this.IsHtmlReport)
			   {
					devInfo = AddDeviceSetting("HTMLFragment", "true", devInfo);
			   }
				
			   result = rs.Render(reportPath, format, historyID, devInfo, reportParameters, credentials, 
				   showHideToggle, out encoding, out mimeType, out reportHistoryParameters, out warnings,
				   out streamIDs);

			   // for multi-stream renders, such as HTML, need to render the report images as streams
			   // so they show in the report
			   // alternatively, if HTTP GET is allowed on the Report Server,
			   // the HTMLFragment device info setting could be used
				if (this.IsHtmlReport)
				{
					foreach (string streamID in streamIDs)
					{
						byte [] image = rs.RenderStream(reportPath, format, streamID, null, null, reportParameters, out optionalString, out optionalString);
						FileStream stream = File.OpenWrite(imageDownloadPath + streamID);
						stream.Write(image, 0, image.Length);
						stream.Close();
					}
				}
		   }
		   catch (SoapException ex)
		   {
			   Trace.WriteLine(ex.Detail.OuterXml);
			   throw ex;
		   }

		   return result;
	   }
		/// <summary>
		/// A simple helper function to add a setting to device info 
		/// </summary>
		/// <param name="settingName"></param>
		/// <param name="settingValue"></param>
		/// <param name="devInfo"></param>
		/// <returns></returns>
	   private static string AddDeviceSetting (string settingName, string settingValue, string devInfo)
	   {
		   if (devInfo == null) devInfo = "<DeviceInfo/>";
		   XmlDocument xmlDoc = new XmlDocument();
		   xmlDoc.LoadXml (devInfo);
		   XmlNode streamRoot = xmlDoc.CreateNode(XmlNodeType.Element, settingName, String.Empty );
		   streamRoot.InnerText =  settingValue; 
		   xmlDoc.ImportNode(streamRoot, false);
		   xmlDoc.DocumentElement.AppendChild(streamRoot);
		   return xmlDoc.InnerXml;
			
	   }

	   private string MessageToHTML(string message)
	   {
		   return "<P style=\"font-family: Verdana; font-size: 11px\">" + message + "</P>" ;
	   }


	   private static string GetFileName (string reportPath, string format)
	   {
		   string fileName = Path.GetFileName(reportPath);
		   string fileExt = null;

		   switch (format.ToLower())
		   {
			   case "html4.0"	: fileExt = "html"; break;
			   case "html3.2"	: fileExt = "html"; break;
			   case "mhtml"		: fileExt = "html"; break;
			   case "htmlowc"	: fileExt = "html"; break;
			   case "excel"		: fileExt = "xls";  break;
			   case "jpeg"		: fileExt = "jpg";	break;
			   case "tiff"		: fileExt = "tif";  break;
			   case "image"		: fileExt = "tif";  break;
			   default			: fileExt = format; break;
		   }

		   fileName = fileName + "." + fileExt;

		   return fileName;
	   }
	   /// <summary>
	   /// Return the content type of the response when the report is streamed back to the browser
	   /// </summary>
	   /// <param name="fileExtension"></param>
	   /// <returns></returns>
	   private string GetContentType(string fileExtension)
	   {
			string contentType = null;

		   switch (fileExtension.ToLower())
		   {
			   case ".pdf"	: contentType = "application/pdf"; break;
			   case ".tif"	: contentType = "image/tiff";	break;
			   case ".xls"	: contentType = "x-msexcel";	break;
			   case ".xml"	: contentType = "text/xml";		break;
			   default		: contentType = "text/plain";	break;
		   }
		   return contentType;
	   }


	   #endregion

	  #region ICustomTypeDesciptor implementation 
	   // in all cases except GetProperties pass-through
	   
	   public System.ComponentModel.AttributeCollection GetAttributes()
	   {
		   // TODO:  Add AwReportViewer.GetAttributes implementation
		   return TypeDescriptor.GetAttributes(this.GetType());
	   }
   
	   public string GetClassName()
	   {
		   return TypeDescriptor.GetClassName(this, true);
	   }

	   public TypeConverter GetConverter()
	   {
		   return TypeDescriptor.GetConverter(this.GetType());
	   }

	   public EventDescriptor GetDefaultEvent()
	   {
		   return TypeDescriptor.GetDefaultEvent(this.GetType());
	   }

	   public PropertyDescriptor GetDefaultProperty()
	   {
		   return TypeDescriptor.GetDefaultProperty(this.GetType());
	   }

	   public Object GetEditor(System.Type editorBaseType)
	   {
		   return TypeDescriptor.GetEditor(this.GetType(), Type.GetType("System.Drawing.Design.UITypeEditor"));
	   }

	   public EventDescriptorCollection GetEvents()
	   {
		   return TypeDescriptor.GetEvents(this.GetType());
	   }

	   public EventDescriptorCollection GetEvents(System.Attribute[] attributes)
	   {
		   return TypeDescriptor.GetEvents(this.GetType(), attributes);
	   }

	   public PropertyDescriptorCollection GetProperties()
	   {
		   return GetProperties(null);
	   }

	   public PropertyDescriptorCollection GetProperties(System.Attribute[] attributes)
	   {
		   PropertyDescriptorCollection filteredProperties = new PropertyDescriptorCollection(null);
		   PropertyDescriptorCollection existingProperties;
		   PropertyDescriptor tempProperty = null;

		   existingProperties = TypeDescriptor.GetProperties(this.GetType(), attributes);
		   foreach (PropertyDescriptor pd in existingProperties) filteredProperties.Add(pd);


			// enable/disable the custom properties based on the report generation option
			tempProperty = filteredProperties["ToolbarVisible"];
			if (tempProperty !=null)
			{
				filteredProperties.Remove(tempProperty);
				tempProperty = TypeDescriptor.CreateProperty(tempProperty.ComponentType, tempProperty, new System.Attribute[] {this.ServerSide == multiState.True?ReadOnlyAttribute.Yes:ReadOnlyAttribute.No});
				filteredProperties.Add(tempProperty);
			}
		   tempProperty = filteredProperties["ParametersVisible"];
		   if (tempProperty !=null)
		   {
			   filteredProperties.Remove(tempProperty);
			   tempProperty = TypeDescriptor.CreateProperty(tempProperty.ComponentType, tempProperty, new System.Attribute[] {this.ServerSide == multiState.True?ReadOnlyAttribute.Yes:ReadOnlyAttribute.No});
			   filteredProperties.Add(tempProperty);
		   }
		   tempProperty = filteredProperties["Zoom"];
		   if (tempProperty !=null)
		   {
			   filteredProperties.Remove(tempProperty);
			   tempProperty = TypeDescriptor.CreateProperty(tempProperty.ComponentType, tempProperty, new System.Attribute[] {this.ServerSide == multiState.True?ReadOnlyAttribute.Yes:ReadOnlyAttribute.No});
			   filteredProperties.Add(tempProperty);
		   }
		   tempProperty = filteredProperties["StreamRoot"];
		   if (tempProperty !=null)
		   {
			   filteredProperties.Remove(tempProperty);
			   tempProperty = TypeDescriptor.CreateProperty(tempProperty.ComponentType, tempProperty, new System.Attribute[] {this.ServerSide == multiState.True?ReadOnlyAttribute.No:ReadOnlyAttribute.Yes});
			   filteredProperties.Add(tempProperty);
		   }
		   tempProperty = filteredProperties["ImageDownloadPath"];
		   if (tempProperty !=null)
		   {
			   filteredProperties.Remove(tempProperty);
			   tempProperty = TypeDescriptor.CreateProperty(tempProperty.ComponentType, tempProperty, new System.Attribute[] {this.ServerSide == multiState.True?ReadOnlyAttribute.No:ReadOnlyAttribute.Yes});
			   filteredProperties.Add(tempProperty);
		   }
		   tempProperty = filteredProperties["DataSource"];
		   if (tempProperty !=null && this.ServerSide!=multiState.True)
		   {
			   filteredProperties.Remove(tempProperty);
		   }

		   return filteredProperties;

	   }
   
	   public string GetComponentName()
	   {
		   return TypeDescriptor.GetComponentName(this, true);
	   }
   
	   public object GetPropertyOwner(PropertyDescriptor pd)
	   {
		   // TODO:  Add AwReportViewer.GetPropertyOwner implementation
		   return this;
	   }
	   #endregion
   }
}


By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) LEN Associates Inc.
United States United States
Years of software consulting and software development using Microsoft development products such as Microsoft Content Management System, SQL Server Reporting Service, ASP.Net C# VB.Net, HTML and javascript web development, Visual Studio add-on development, C++ MFC/ATL and COM+ development, and ActiveX components.

Comments and Discussions