I want to get back into the habit of blogging.
I’m currently learning the ASP.NET MVC3 framework. I’m going to be blogging about things I have learned while using the framework.
Hope you enjoy it.
The "Eureka!," "How could I be so stupid!," and "Head-to-Wall-Banging" aspects of Programming and Life, served with a side order of humor and alternate perspective.
I want to get back into the habit of blogging.
I’m currently learning the ASP.NET MVC3 framework. I’m going to be blogging about things I have learned while using the framework.
Hope you enjoy it.
I am working on a SQL Server Reporting Services 2008 project. I decided to write a tool in C# that will document the reports that I have created.
What should make this easy is that the structure of the RDL (report) file is XML, which makes it a perfect candidate for using LINQ to XML to dig through its information.
Here’s the top of the RDL file I’m trying to process (C:\MyReport.RDL):
<?xml version="1.0" encoding="utf-8"?><Report xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner" xmlns="http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition"><DataSources><DataSource Name="SalesDM"><DataSourceReference>SalesDM</DataSourceReference><rd:DataSourceID>60c7781c-ab9c-4c5f-b779-24afa5d5bac3</rd:DataSourceID><rd:SecurityType>None</rd:SecurityType></DataSource></DataSources><DataSets>...
I wrote the following code to parse the file:
// Load report into an XDocumentXDocument doc = XDocument.Load(@"C:\MyReport.RDL");// Grab the DataSourceIDs of all the data sourcesvar dataSources = (from ds in doc.Descendants("DataSource")select ds.Element("DataSourceID").Value).ToList();
But for some reason, dataSources didn’t contain any results.
I found information on the web that said that I needed to create an XNamespace instance, and point it to the namespace defined in the xmlns: attribute at the top of the RDL file in the <Report> element. This XNamespace instance is then used when calling the Descendants() method of an XDocument.
What is slightly confusing is that at first glance, the <DataSource> element does not seem to have a namespace (as opposed to the DataSourceID element, which has the “rd:” prefix, signifying a namespace )
Here’s the trick: notice that the XML namespace:
xmlns=”http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition”
doesn’t have a prefix (ex. “rd:”) – it is therefore the default XML namespace of all child elements of the <Report> element. Now that we know the namespace, we have to tell LINQ to XML what the namespace is when querying:
// Load report into an XDocumentXDocument doc = XDocument.Load(@"C:\MyReport.RDL");// Get the XML namespace for the default namespace of the RDL fileXNamespace ns = XNamespace.Get("http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition");// Grab the DataSourceIDs of all the data sourcesvar dataSources = (from ds in doc.Descendants(ns+"DataSource")select ds).ToList();
Prefixing “DataSource” with the namespace instance (ns) causes the LINQ query to return one item as expected.
All that we need to do to find the DataSourceID of the element. We just access the Element() method of ds, right? Close, but not quite. Take another look at the XML for the DataSourceID element:
<rd:DataSourceID>60c7781c-ab9c-4c5f-b779-24afa5d5bac3</rd:DataSourceID>
It has a different namespace than the element it is contained by. We must apply the same technique with a different XNamespace instance (ns2) when calling the Element() method. Here’s the final (working) code:
XDocument doc = XDocument.Load(@"C:\MyReport.RDL");// Get the XML namespace for the default namespace of the RDL fileXNamespace ns = XNamespace.Get("http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition");// Get the XML namespace for the rd: namespace of the RDL fileXNamespace ns2 = XNamespace.Get("http://schemas.microsoft.com/SQLServer/reporting/reportdesigner");// Grab the DataSourceIDs of all the data sourcesvar dataSources = (from ds in doc.Descendants(ns + "DataSource")select ds.Element(ns2+"DataSourceID").Value).ToList();
I hope this saves you some time!
Recently I noticed that a component I have been working on was running slowly in its Release version. The only changes I had made recently were mostly calls to Debug.WriteLine() to get unit-testing information. When I figured out the problem, it reminded me of a term from my Psychology background (my degree in Psychology, not my therapy ;-) ) called the “Observer Effect.”
The Observer Effect is a term in experimental research which basically says that while you are trying to observe something, the very act of observation might affect what you are trying to observe.
Consider the following simple, albeit silly example :
Hypothesis: Water freezes at zero degrees Celsius.
Method of study: Stand in freezer holding small puddle of water in hand.
Results: Water doesn’t freeze at zero degrees Celsius.
Why? Because the method of observation (holding water in hand) prevents the water from freezing because the warmth of your hand (around 98.6F) warms the water sufficiently so that it doesn’t freeze.
So how does that relate to testing?
We all have put calls to System.Diagnostics.Debug.WriteLine() in our code to help with debugging or to validate assumptions. This is our “observation method.” One of the side benefits of using Debug.WriteLine() is that the compiler will ignore these lines when building a Release version of your code. It is as if the code never existed.
Why is this important? Let’s say that you wrote a generic method that loops through a List<>, writing out the contents of the list:
public static void LogList<T>(string name, List<T> items)
{
Debug.WriteLine("== " + name + ": " + items.Count.ToString() + " items.==");
int counter = 0;
foreach (T item in items)
{
Debug.WriteLine(String.Format("[{0}] - {1}", counter, item));
counter++;
}
Debug.WriteLine("==End of contents of " + name+ "==");
}
In this case, where you call LogList() in your code, LogList runs both in Debug and Release versions. Only the calls to Debug.WriteLine() are ignored by the compiler. If this is a particularly long list, or if there’s a time consuming part of this method, your Release executable will be slower.
The good news is that there is an easy fix: the Conditional attribute. The conditional attribute can be applied to methods, and looks like the following:
[Conditional("<symbol to test for>")]When Visual Studio calls the compiler to compile a Debug version, it passes the symbol DEBUG as part of the command line. When Visual Studio calls the compiler to compile a Release version, it passes the symbol RELEASE as part of the command line.
The Conditional attribute tells the compiler to only include this method if the symbol exists. So if we simply add the following conditional attribute to our method:
[Conditional("DEBUG")]
public static void LogList<T>(string name, List<T> items)
Now the compiler will include this method in the compiled output only if DEBUG is a symbol (the compiler is building a Debug version).
You might be saying to yourself, “Rick, that only takes care of the method itself. What about all the calls to that method, spread out all over my application?”
The beauty of the conditional attribute is that the compiler ignores all of the calls to the function too!
I love creating tools that simplify a developers life and can save time.
My intent with the next few blog entries will be to publicly step through the process of designing, creating, and using tools that I have named the "Fast and Filthy Add Ins for Visual Studio."
"Fast and Filthy" is a play on the term "Quick and Dirty." These add ins will be Visual Studio add ins that will give a developer a fast and simple way to create prototypes for customers/management. I think this also has the potential for use by managers and even clients (more on this later).
Classes, controls, and data tend to be hierarchical in nature. Classes have properties and methods (which have parameters and a return value ). Controls contain collections of controls. Data tends to be hierarchical to some degree - Databases contains tables which can be related to other tables, tables contain fields, etc.. And then of course there's XML: hierarchical-incarnate. You get the point.
Visual Studio and the .NET framework have proven that this information (as well as everything from project files to type libraries to comments) can be represented in a single flexible format: XML. Designing in XML, though, can be a bit tedious. For example, I love the power that XAML provides, but XAML has not made coding quicker or easier in my opinion.
I think that it is possible to express classes, controls, etc in a simple, text-based, non-graphical (and for that matter language agnostic) way. Basically, take the contents of a textbox and apply some fairly simple rules to create/convert into the desired outcome.
The simplest and most direct example of this would be treeview control. If you've ever manually filled a treeview control, you know what I mean. If you take the graphical approach, you are living in the collecti0n/TreeNode UIEditor scrolling through mini property windows:
If you take the programmatic approach, you are building and connecting parent and child nodes:
Dim parentNode As TreeNode
Dim childNode As TreeNode
parentNode = TreeView1.Nodes.Add("Node0")
childNode = New TreeNode("Node2")
parentNode.Nodes.Add(childNode)
parentNode = TreeView1.Nodes.Add("Node1")
childNode = New TreeNode("Node3")
parentNode = childNode
childNode = New TreeNode("Node4")
parentNode.Nodes.Add(childNode)
Consider this for a moment: a textbox with AllowTabs set to True (so that tab characters can be typed within the text box). You type the following into the textbox:
| Node0 | ||
| Node2 | ||
| Node1 | ||
| Node3 | ||
| Node4 | ||
This text can easily be parsed to create a treeview. Furthermore, you can move nodes around much easier in the text box. For example, if I wanted to make Node4 the child of Node2, then I can cut the Node4 line, and then paste it under Node2:
| Node0 | ||
| Node2 | ||
| Node4 | ||
| Node1 | ||
| Node3 | ||
Much easier than changing it through the designers or code.
You might say that with this method you lose some of the finer control (icons, bolding, etc) of the nodes. I agree, but you could add some new rules to the parsing. For example, to use the first few characters of the text to influence rendering:
| (0)Node0 | ||
| (1)Node2 | ||
| (2)Node4 | ||
| ^(0)Node1 | ||
| ^(1)Node3 | ||
"^" could mean the node is a checkbox node, and a number in parens could the imagelist index of the image to use on the node.
You are essentially "drawing" a treeview with simple text.
Consider the following text for generating a dataset:
| Customer | ||
| *Customer_ID | ||
| sName | ||
| bIsActive | ||
| Orders | ||
| *Orders_ID | ||
| @Customer_ID | ||
| dOrderDate | ||
| dShipDate | ||
| Customer->Orders | ||
This text could:
Pretty cool, huh?
Now lets take this one step further - the same text for the dataset could be used to generate TSQL to create the structure in a SQL Server database! If you hang on to the text (embed it in a comment for example) you can keep the dataset and database in sync.
Heck, if you think about it - the same text used in the Dataset example could be used to generate classes with properties and collections (Customer could have a List(Of Orders) due to the Customer->Orders line). All that's missing is methods, which could easily be created by putting parens at the end of the text (e.g. Execute() )
Earlier I mentioned that these add-ins could be used by management or clients.
I see the the text blocks as a short hand for creating prototype GUIs and data. They can create their own prototypes (with a little training). Maybe even compile the prototype into an executable that could be distributed to people. A "managers tool" could be created as a VS Package IDE so that managers would not need to have Visual Studio installed.
Analysts could open the package and design the prototype right in the meeting as people are talking about it. A great way to build a concencus in my opinion.
They can then approach the developer with the prototype, and demo what they would like to see. I think that is a much easier approach than having the someone try to describe an interface in a specification. Or it could provide them with screen shots that become part of the specification. I'm not saying that managers/clients are the best designers, but I think giving them such a tool would empower them.
At least they can generate talking points, and with a little tweaking serve as system documentation.
Next I will be talking about ideas on how to implement these features. And once the code becomes more solid, I will put it up on Codeplex.
This is a work in progress, and I would appreciate any comments on the the ideas presented here (positive and negative). It can only serve to improve the final output.
Take Care!
Sorry for the delay in blog entries - the lines for the bathroom at my house are way long. ;-)
Seriously, I've been away a while, but I'm going to throw myself into blogging. I encourage you to stay tuned!




If the Iterator I'm using to walk the string (ex. oIterator) is pointing at a double quote character