Click here to Skip to main content
13,295,616 members (38,288 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as


39 bookmarked
Posted 8 Feb 2010

Dynamic Reports with Reporting Services

, 8 Feb 2010
Rate this:
Please Sign up or sign in to vote.
This article demonstrates how to generate SSRS reports based on an input DataTable.


The article explains a simple method to generate simple reports using Reporting Services 2005 and a few XML on C#. SSRS does not allow us to generate dynamic tables based on the content of a C# data container object, but sometimes it is useful to create a report programmatically based on DataTable (or DataSet) structure.   

The Code

My need was generating reports from a generic DataTable, because I cannot access the database directly, so I've written this code.
First of all I studied .rdl files, in fact this file format is simple XML with a few required tags you require to know.
I used XmlWriter class to write the XML, and ReportViewer's LocalReport mode has a method LoadReportDefinition that accepts a Stream object, that is our XML produced with XmlWriter.
These are the private variables that are required for my class:

private CultureInfo ci = new CultureInfo("en-US");
private string nsRd = "";
private string ns = 

The CultureInfo object serves because my default is it-IT, and Reports require a dot as the float decimal separator.
Other two strings are the namespaces required for the report in order to be validated and accepted by ReportViewer.
XmlWriter class requires, in my case, a StringBuilder and an XmlSettings object, this is how I've set this last.

#region Settings
XmlWriterSettings settings = new XmlWriterSettings();
settings.CheckCharacters = true;
settings.CloseOutput = true;
settings.Encoding = Encoding.UTF8;
settings.Indent = true;
settings.IndentChars = "\t";
settings.NewLineChars = "\r\n";
settings.NewLineHandling = NewLineHandling.Replace;
settings.NewLineOnAttributes = false;
settings.OmitXmlDeclaration = false;

Writing XML with XmlWriter is quite simple and does not require much explanation, but setting the columns' width based on passed data requires it.
This is the method that gets the size of a string and I used it in my code as below:

private SizeF GetDynamicSize(string s)
	Font f = new Font(FontFamily.GenericSansSerif, 10);
	Bitmap bmp = new Bitmap(1, 1);
	Graphics g = Graphics.FromImage(bmp);
	g.PageUnit = GraphicsUnit.Millimeter;
	SizeF ret = SizeF.Empty;
	ret = g.MeasureString(s, f);
	return ret;


// This is the TableColumns section which pretends the same number of tags
// as columns of data table, and requires the width of each column
// This is how I've implemented (dt variable is the DataTable object with data inside):

{ // These brackets are only for more readability of the code. 
  // XML is folded and my code too.
	for (int i = 0; i < dt.Columns.Count; i++)
			DataColumn dc = dt.Columns[i];
			float sizeWidthComputed = 0.0F;
			float RowMaxLength = 
				GetDynamicSize(dt.Rows[0][i].ToString()).Width / 10;
			float HeaderMaxLength = 
				(GetDynamicSize(dc.ColumnName).Width / 10) + 0.2F;
			foreach (DataRow row in dt.Rows)
				float rowSizeWidth = 
				    GetDynamicSize(row[i].ToString()).Width / 10;
				if (rowSizeWidth > RowMaxLength)
					RowMaxLength = rowSizeWidth;

			if (RowMaxLength > HeaderMaxLength)
				if (RowMaxLength > MaxWidth)
					sizeWidthComputed = MaxWidth;
					sizeWidthComputed = RowMaxLength;
				sizeWidthComputed = HeaderMaxLength;

				(sizeWidthComputed).ToString(ci) + "cm");

Another point of interest of my code is setting dataset and datasource in the report XML. Obviously report requires only one dataset and datasource because one datatable is passed, but you can implement more than one, but you have to make a distinction between tables.
The dataset is important and is more important than dataset and datasource has the same name as the ReportDataSource object required for using the code (in the below named section).

// dsName is the datasource name and in fact it is the name you give 
// at the data source in report viewer control, and dt is the datatable with data inside.
	writer.WriteAttributeString("Name", dsName);
			for (int i = 0; i < dt.Columns.Count; i++)
				("Name", dt.Columns[i].ColumnName);
					("DataField", dt.Columns[i].ColumnName);
					("rd", "TypeName", nsRd, 

			writer.WriteElementString("DataSourceName", dsName);
				("CommandText", ""); // the command text in 
				// query tag may be blank because 
				// we don't have a query at all. This isn't wrong.
				"DataSourceName", nsRd, "true");

// The DataSource section
		writer.WriteAttributeString("Name", dsName);
		writer.WriteElementString("DataSourceReference", dsName);

Rest of the code is building the other XML and setting paddings (in pt) and dimensions, positions and more (in cm or inches if you want). You can get all that in the code, but the most important functions are these.

Oh most important is that you could name details values in textboxes contained in tablecells as "=Fields!{0}.Value", the same as below.

CellColors colors = null; // this is a custom object I made, 
	// fell free to recreate and improve as you want, but make me aware of that.
// Sorry for the italian names :-)
switch (sezione) // Translated "section" (I mean a section of the table)
	case SezioneTabella.Header: // This is a custom enum, "TableSection" translated.
			nomeSezione = "Header";
			templateValore = "{0}";
			colors = new CellColors(Color.Black, Color.White);
	case SezioneTabella.Details:
			nomeSezione = "Details";
			templateValore = "=Fields!{0}.Value";
	case SezioneTabella.Footer:
			nomeSezione = "Footer";
			templateValore = "{0}";
	if (sezione == SezioneTabella.Header)
		writer.WriteElementString("RepeatOnNewPage", "true");
				("Height", height.ToString(ci) + "cm");
				for (int i = 0; i < dt.Columns.Count; i++)
							valore = String.Format
							// This method generates 
							// a textbox for the 
							// report, it is in the 
							// code and below.
							"textbox" + nomeSezione + 
							i, RectangleF.Empty, 
							padding, colors, valore);

//Generation of a text box for the report table cell.
//Padding and CellColors are my custom objects, in the zip
private void GeneraTextBox(XmlWriter writer, string textboxName, 
	RectangleF dimensioni, Padding padding, CellColors colors, string value)
	writer.WriteAttributeString("Name", textboxName);
		writer.WriteElementString("rd", "DefaultName", nsRd, textboxName);
		if (dimensioni != RectangleF.Empty)
				dimensioni.Top.ToString(ci) + "cm");
				dimensioni.Left.ToString(ci) + "cm");
				dimensioni.Width.ToString(ci) + "cm");
				dimensioni.Height.ToString(ci) + "cm");
		writer.WriteElementString("CanGrow", "true");
		writer.WriteElementString("Value", value);
		if (padding != null)
						("Default", "Solid");

				if (colors != null)
					("Color", colors.ForegroundColor.Name);

					padding.Left.ToString(ci) + "pt");
					padding.Right.ToString(ci) + "pt");
					padding.Top.ToString(ci) + "pt");
					padding.Bottom.ToString(ci) + "pt");

//My custom objects

public enum SezioneTabella

public class CellColors
	public CellColors(Color bg, Color fore)
	{ = bg;
		this.fore = fore;
	private Color bg = Color.Empty;
	private Color fore = Color.Empty;

	public Color BackgroundColor { get { return bg; } }
	public Color ForegroundColor { get { return fore; } }

public class Padding
	public Padding(float Top, float Left, float Bottom, float Right)
		TopLeft = new PointF(Left, Top);
		BottomRight = new PointF(Right, Bottom);

	private PointF TopLeft { get; set; }
	private PointF BottomRight { get; set; }

	public float Top { get { return TopLeft.Y; } }
	public float Left { get { return TopLeft.X; } }
	public float Bottom { get { return BottomRight.Y; } }
	public float Right { get { return BottomRight.X; } }

I think this is pretty much all of the highlights I have to do with this code, you can try more or you can use the code, that generates a simple table of nearly any dataset.
An advertise, DataSet and DataSource names have to be only Letters, no special characters and no other chars than letters, I've written below.

Using the Code

All you have to do with this simple class is instantiate a ReportDataSource object and pass it to the ReportGenerator, then call GenerateReport() method as argument for the LoadReportDefinition method of the ReportViewer control.

DataTable data = new DataTable(); 	//This would be your own DataTable, 
				//none particular features requested.
string dsName = "", displayName = ""; // These are your display name 
				// and data source name,
//display can be anything you want but data source only accepts Letter characters, 
//no spaces, no underscores,
//none other than Letters (or numbers but this is not the case).
//I give you a little snippet for the data source name:
char[] ctext = stringToCleanForDataSource.ToCharArray();
for (int i = 0; i < ctext.Length; i++)
        if (Char.IsLetter(ctext[i])) dsName += ctext[i];
ReportDataSource ds = new ReportDataSource(dsName, data);
ReportGenerator gen = new ReportGenerator(data, dsName);
ReportViewer1.LocalReport.DisplayName = displayName;

The complete ReportGenerator class is in the zip file and can be downloaded from the link at the top of this article.


  • 8th February, 2010: Initial post


This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


About the Author

Software Developer (Junior)
Italy Italy
No Biography provided

You may also be interested in...


Comments and Discussions

QuestionAdd Space and Numbers Pin
Member 1332960323-Aug-17 21:12
memberMember 1332960323-Aug-17 21:12 
QuestionHow to implement this code Pin
sazan8021-Aug-16 18:35
membersazan8021-Aug-16 18:35 
AnswerRe: How to implement this code Pin
kLeZ-hAcK27-Sep-16 2:35
memberkLeZ-hAcK27-Sep-16 2:35 
QuestionAdding Header Information Pin
Prajwal Bhat26-Nov-15 3:45
professionalPrajwal Bhat26-Nov-15 3:45 
QuestionHow I can use this code to add multi datatable at runtime from select database Pin
TaherAlqadsi16-Nov-15 2:36
memberTaherAlqadsi16-Nov-15 2:36 
Questionthis works! Pin
Rochelle Velasquez-Macazo9-Nov-15 11:51
memberRochelle Velasquez-Macazo9-Nov-15 11:51 
QuestionCan we do the same in SSRS 2008 R2 Pin
vipul200819-Aug-15 23:26
membervipul200819-Aug-15 23:26 
AnswerRe: Can we do the same in SSRS 2008 R2 Pin
vipul200819-Aug-15 23:36
membervipul200819-Aug-15 23:36 
QuestionHow can I add grouping on columns using the same code Pin
Member 1153438624-Mar-15 4:01
memberMember 1153438624-Mar-15 4:01 
QuestionColumn Header Widths Pin
Member 462571318-Jul-14 8:07
memberMember 462571318-Jul-14 8:07 
QuestionGrouping of Rows Pin
aggaton20-Dec-13 11:35
memberaggaton20-Dec-13 11:35 
QuestionBrilliant and oh, so very useful! Pin
Member 462571317-Dec-13 9:01
memberMember 462571317-Dec-13 9:01 
GeneralTruly Genius Pin
BM Britto24-Oct-13 0:34
memberBM Britto24-Oct-13 0:34 
QuestionPage throws Error Pin
davita-ostati16-Sep-13 5:44
memberdavita-ostati16-Sep-13 5:44 
QuestionDynamic Reports with Reporting Services Pin
xanilkumar25-Jul-13 22:43
memberxanilkumar25-Jul-13 22:43 
QuestionHow to add parameters to this report Pin
Member 100893374-Jun-13 22:47
memberMember 100893374-Jun-13 22:47 
AnswerRe: How to add parameters to this report Pin
coded0075-Jun-13 6:01
membercoded0075-Jun-13 6:01 
GeneralRe: How to add parameters to this report Pin
MithunKhadloya5-Jun-13 7:44
memberMithunKhadloya5-Jun-13 7:44 
QuestionDisplay data of multiple tables Pin
GauravDac20-Feb-13 4:31
memberGauravDac20-Feb-13 4:31 
AnswerRe: Display data of multiple tables Pin
kLeZ-hAcK20-Feb-13 5:10
memberkLeZ-hAcK20-Feb-13 5:10 
GeneralRe: Display data of multiple tables Pin
GauravDac20-Feb-13 21:13
memberGauravDac20-Feb-13 21:13 
GeneralMy vote of 5 Pin
sudarvendhan16-Oct-12 20:22
membersudarvendhan16-Oct-12 20:22 
QuestionImage Pin
Shargon_855-Jun-12 21:34
memberShargon_855-Jun-12 21:34 
GeneralMy vote of 5 Pin
Reza Ahmadi21-Apr-12 2:37
memberReza Ahmadi21-Apr-12 2:37 
GeneralFor some people Pin
ltlsoft21-Mar-12 2:57
memberltlsoft21-Mar-12 2:57 
QuestionThanks to all for your comments Pin
kLeZ-hAcK24-Feb-12 0:56
memberkLeZ-hAcK24-Feb-12 0:56 
AnswerRe: Thanks to all for your comments Pin
vipul200819-Aug-15 23:25
membervipul200819-Aug-15 23:25 
Questiongreat work Pin
sethy12324-Feb-12 0:39
membersethy12324-Feb-12 0:39 
GeneralGood work Pin
c#ivan14-Jun-11 5:59
memberc#ivan14-Jun-11 5:59 
Excellent article.
GeneralMy vote of 5 Pin
raja_krish31-May-11 11:07
memberraja_krish31-May-11 11:07 
GeneralMy vote of 5 Pin
Pranay Rana30-Jul-10 0:56
memberPranay Rana30-Jul-10 0:56 
GeneralGood job Pin
a codeproject fan9-Jun-10 7:27
membera codeproject fan9-Jun-10 7:27 
GeneralCode is not accessible Pin
kaminm8-Feb-10 14:48
memberkaminm8-Feb-10 14:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.171207.1 | Last Updated 8 Feb 2010
Article Copyright 2010 by kLeZ-hAcK
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid