Just saw this on Channel 9 - http://bit.ly/ojq6Hk. It refers to a blog post by Gal Ratner, http://bit.ly/p093H7. Discussion on Skype API and source code for how to attach to Skype process and redirect conversations allowing you to record them. Check it out.
Among its many qualities, I found that reflector! always had a remarkable ability to just disappear from my machine when I called upon it. It’s not every day that one needs to view the source code of some binary, but occasionally I would find myself looking at the IL generated by my code, and I’m not a big fan of viewing it from ildasm. I never figured out the interval, but it seemed that when a new version of reflector came out, the one you had would leave you stranded. And one day, it never came back.
It so happens that Telerik has a similar tool still in beta called Just Decompile. I just installed it this afternoon and have been playing around with it, seeing how it presents the code in the different languages. It doesn’t support all the languages that reflector did, but the most obvious choices, IL, C# and VB are there. From the feel of the app, I think it was written using WPF, but if you take that point to the bank, you might not redeem it for money.
Interface
The UI is quite simple to understand, with just one toolbar and a collapsible menu bar.
The Load Framework menu includes options to load a framework of your choice, defaults are .NET 2.0, .NET 4.0 and the Silverlight assemblies. The assembly list option allows you to load or create custom assembly lists.
An interesting command on the toolbar is the Create Project button next to the Language selection combo box. This allows you to decompile an assembly and save the code in a new .NET project. This feature is only available when you select C# as your language.
Issues
Just Decompile seems stable enough, but I have seen some error messages when trying to open some methods in VB or C#. So far there hasn’t been a problem in IL though. Following are some of the issues I’ll be reporting soon. The classes that cause errors in C# will still raise errors in the project creation process, but the process itself is unaffected because it will just continue decompiling the ones it can.

It also seems the C# code generator (if I can call it that) works better than the VB one. As some methods I tried work in IL and C# but not VB. It also displays auto implement properties fully expanded in VB.
Because of a rather curious issue, I haven’t been able to view Interface definitions in VB for interfaces that have properties. Anyway as this is still in beta, I’m pretty sure it will get fixed by the time it gets released. Despite these issues, there are no show stoppers to worry about.
Conclusion
All in all, this is looking like a great product and the best part about it is that Telerik guarantees that it will remain free forever! Now, there is no definitive evaluation of how long forever is, but I take it to mean a very long time indeed. And finally I must say thanks to Telerik for supporting my favorite podcast, .NET Rocks!
While randomly clicking through links online, I chanced upon an interesting piece of code at The Madman Scribblings. The first thing that interested me was that he had come up with an interesting variation to the If(Condition, Expression, Expression) operator that used Delegates for the expressions.
While I was try to think of ways this would be useful, I then came to the end of the short blog post, where he re-writes another method he had come up with, UpTo. This calculates a range of characters similar to how you can loop through a character range in C# using a for statement.
For those who haven't tried, C# treats Chars like integers and they can be traversed as such using code like this:
class Program
{
static void Main(string[] args)
{
for (char c = 'a'; c <= 'z'; c++)
Console.Write(c);
Console.WriteLine();
}
}
in VB, code like this does not work. I suppose the decision was made because historically the way to deal with characters and integers has always been using Chr and ChrW for finding the character corresponding to a particular integer value, and Asc and AscW for finding the numeric value that represents a particular character. Whatever the reasons, to achieve the same, one would have had to write code like this:
For c = AscW("a"c) To AscW("b"c)
Console.Write(ChrW(c))
Next
Console.WriteLine()
As you can see, you must first get the numeric values representing the characters, and in each iteration, you then calculate the corresponding character from the values you'd have obtained in the first step. C# is doing this for you in the background but this way of writing isn't too pretty, and this isn't the sort of thing you'd want to write multiple times if you need to calculate character ranges a lot. It's not something I do a lot so I just accepted the way VB does it, and just thought there must be some other way of doing it without writing this kind of loop all the time.
The UpTo extension method provides this very thing. It was so relevant to something I had long seen but never tackled that I was more interested in it than the main topic of the blog, the nifty If and IfElse extension methods.
Needless to say, I tried the code on my computer and came upon these minor issues.
- In UpTo, Math.Abs() was generating an overflow because the calculation handed to it resulted in a negative value which is invalid for a Byte. I figured he must have been using Option Strict Off so I used Type inference to make the types Integers instead of removing Option Strict.
- Inside IfElse, there was a syntax error at ElseThis) which I corrected this way elseThis(source)
- And the naming convention I use disallows underscores in method names so I removed these and the methods became If and IfElse instead of _If and _IfElse.
- I also shortened the code by using one line Lambda expressions instead of the multi-line versions.
Here is the result of my changes:
''' <summary>
''' Provides If(Boolean, Object) like functionality for IEnumerable(Of T) using a Delegate as the expression.
''' </summary>
''' <typeparam name="T">The type in the IEnumerable.</typeparam>
''' <param name="source">The source collection that we are looking at.</param>
''' <param name="condition">The condition with which to evaluate the source collection.</param>
''' <param name="doThis">Operation to perform if the condition is True.</param>
''' <returns>Result of doThis(source) if condition is True, source otherwise.</returns>
<Extension()>
Public Function [If](Of T)(ByVal source As IEnumerable(Of T), ByVal condition As Func(Of Boolean),
ByVal doThis As Func(Of IEnumerable(Of T), IEnumerable(Of T))) As IEnumerable(Of T)
Return If(condition(), doThis(source), source)
End Function
''' <summary>
''' Provides If(Boolean, Object, Object) like functionality for IEnumerable(Of T) using a Delegate as the expressions.
''' </summary>
''' <typeparam name="T">The type in the IEnumerable.</typeparam>
''' <param name="source">The source collection that we are evaluating.</param>
''' <param name="condition">The condition with which to evaluate the source collection.</param>
''' <param name="doThis">Operation to perform if the condition is True.</param>
''' <param name="elseThis">Operation to perform if the condition is False.</param>
''' <returns>Result of doThis(source) if condition evaluates to True, else the result of elseThis(source) is returned.</returns>
<Extension()>
Public Function IfElse(Of T)(ByVal source As IEnumerable(Of T), ByVal condition As Func(Of Boolean),
ByVal doThis As Func(Of IEnumerable(Of T), IEnumerable(Of T)),
ByVal elseThis As Func(Of IEnumerable(Of T), IEnumerable(Of T))) As IEnumerable(Of T)
Return If(condition(), doThis(source), elseThis(source))
End Function
''' <summary>
''' Calculates all the characters in the range fromChar to toChar inclusive.
''' </summary>
''' <param name="fromChar">The start character in the sequence.</param>
''' <param name="upToChar">The last character in the sequence.</param>
''' <returns>A string containing all the characters in the range.</returns>
''' <remarks>
''' If fromChar appears after upToChar in alphabetic order, the values are switched around so that an ordered list comes.
''' </remarks>
<Extension()>
Public Function UpTo(ByVal fromChar As Char, ByVal upToChar As Char) As String
Dim f = AscW(fromChar)
Dim u = AscW(upToChar)
Return Enumerable.Range({f, u}.Min, Math.Abs(u - f) + 1).
Select(Function(c) ChrW(c)).If(Function() f > u, Function(x) x.Reverse()).ToArray()
End Function
The above should be placed inside a Module. The following is an example of how to call this method.
Sub Main()
Dim startChar = "Z"c
Console.WriteLine(startChar.UpTo("A"c))
End Sub
I hope you find this as interesting as I did. Happy coding.
Well, I've used up all my sick days so tomorrow I'm calling in dead. In the meantime, I thought of posting a review on a couple of things I have learned over the past few months. The first thing I will work on is code to deal with Jump Lists. My first post on the subject was after my first attempt and doing things the old way, in code. Code junkies like me who've been coding since the green screen days of MS-DOS will probably attack a problem in code first. WPF has changed that in that you can achieve a lot of the same results without writing a single line of executable code. XAML is the answer.
Well, I finally worked on a real app that would benefit a lot from jump lists. And this time, I approached it using XAML. The application even had an overlay icon to notify the user when a long running asynchronous operation was in progress.
Jump Lists
The first file I edited when trying this in XAML is the Application.xaml (app.xaml for C#). This is because the Jump List belongs to the application.
<JumpList.JumpList>
<JumpList JumpItemsRejected="JumpList_JumpItemsRejected" JumpItemsRemovedByUser="JumpList_JumpItemsRemovedByUser">
<!-- Add ApplicationPath attributes to point to the app you wish to run when your task is clicked.
You can also place an Arguments attribute which can specify command line arguments for the app.
You can also assign an Icon to the task by specifying an IconResourcePath attribute. -->
<JumpTask Title="Calculator" Description="Launch the windows calculator"
IconResourcePath="C:\Windows\System32\Calc.exe" ApplicationPath="C:\Windows\System32\Calc.exe" />
<JumpPath Path="C:\Users\Public\Readme.txt" />
</JumpList>
</JumpList.JumpList>
This piece of XAML registers event handlers to deal with the scenarios when a jump item is rejected, or when a user removes it from the list. In the second scenario it is recommended that you skip loading the item the next time your app runs to respect the user's wishes.
It then adds a JumpTask that runs the windows calculator, and a JumpPath. For the jump path to register, you should register your application to open the file type in question.
Overlay Icon
The overlay icon is very simple too. In this case, I wrote one line of code to remove the icon, and one other to remove it. Here is the XAML for it.
<Window.TaskbarItemInfo>
<TaskbarItemInfo />
</Window.TaskbarItemInfo>
<Window.Resources>
<DrawingImage x:Key="IconOverlay" >
<DrawingImage.Drawing>
<ImageDrawing ImageSource="Offline.png" Rect="0 0 32 32" />
</DrawingImage.Drawing>
</DrawingImage>
</Window.Resources>
You place this in the .xaml file for the main window. In this case, the source is a png, but it can be an icon. The code to show and hide the icon in the task bar follows:
' To add the overlay icon.
Me.TaskbarItemInfo.Overlay = CType(Me.Resources("IconOverlay"), ImageSource)
' To remove the overlay icon.
Me.TaskbarItemInfo.Overlay = Nothing
That's it. Here is the same in C#.
// Add the overlay icon.
this.TaskbarItemInfo.Overlay = (ImageSource)this.Resources["IconOverlay"];
// Remove the thing.
this.TaskbarItemInfo.Overlay = null;
That's really all you have to do.
Conclusion
In a production app you'll need to do more however. You may have more than one scenario in which you'd want to show an overlay icon, in this case, you'll need to handle the various events or situations that fit your application. In the case of the jump list, you may want to load your jump items dynamically so you can determine what the user wishes to see or to reflect the overall status of the application. There's no point in having a "Publish Local Data" if there is no local data to publish.
Hope this helps. Happy coding.
Boy, doesn't time move fast. It seems like only a few months ago when I downloaded VS2010 Beta 2 and now the release candidate is here. Okay, so it actually was a few months ago when I did the download, but you get the point don't you? I haven't done any coding in almost a month so I missed this when it came out and only saw it it this morning when I opened Beta 2. This has come out sooner than I expected, and that's a good thing.
I'm just looking at some of the new features available in it (from the MSDN website), and it appears they have a prototyping tool, and from the screen shot available, it seems it has similar functionality to sketchflow. But this works from inside Visual Studio, which is great for left-brained developers like me who know how to use Blend through and through, but still cannot create something appealing to the eye with the tool. The page is offering new integration capabilities for the various roles we have to fill, (developer, designer, tester, etc.), which if improved will totally rock because I think they are great already.
You can aslo see from the MSDN site that as expected, there is a lot of chatter about it on twitter. I don't know about you, but I'm game, and will be downloading this to see what new things it has to offer.
I’m thoroughly enjoying the nice new features in VS2010 and the little features offer the best wow moments for me.
I was working on an app a couple of days ago that used LINQ and anonymous types and I now had to pass the result of the query to a procedure in another class for storage. This meant I had to write out a class and replace the reference to the anonymous type with the name of the class I had been using.
I tried something new first, by writing the intended name of the class, and generating the class from usage. Doing this was a breeze as I accomplished everything in one step from VB. It generated auto implement properties based on the object initializer and I thought this was cool.
Here is a step-by-step guide on how to accomplish this…
At this point, you add the name of the class….
then invoke the generate from usage smart tag
At which point we are done. Here is the class that VB generated…
I think it is so cool, the way VS2010 makes you more productive. All I had to do was 4 keystrokes, A-p-p-<space> (in the context of the example I am using) and then all was well. The method in the class I was working on now had to reference the name of the class that I specified.
There are some differences however in that there is one method of anonymous types in VB that makes the type immutable, and you can have another way that you can edit the values. C# generates immutable anonymous types only. If you want similar semantics for your generated class, you will have to expand the properties and implement them as write-once, read-only (in which case you will have to call a constructor as opposed to using object initializers). I’ll get around to doing this in C# and posting on how to do it in that language although I can’t imagine the process being too different.
Hope this helps, happy coding.
After the formatting disaster that was my attempt at posting about JumpLists in Windows 7, I tried in vain to change the font and other attributes. It turned out that even the attached download didn’t work properly.
I have had to start afresh on a new PC and re-typed the whole document in Windows Live Writer to get the formatting anywhere near correct. I re-uploaded the download and have tested to see that it does work. Hopefully now it will be easier to read.
I’m a firm believer in the mantra “When all else fails, read the instructions.” For most items, I just get stuck into what I need to do and figure out the details on the way. This is what I did when I started using VS2010 beta 2. I have never used a beta 1 product before, and I’m usually hesitant to try out beta 2 products, but I wasted no time with VS2008 and VS2010 because of the huge potential they carry.
As soon as my installation was done I opened Visual Studio and started to write some code. This was cool. I then unpacked the samples to see how some of the new things were done, and then finally I started to apply some of the new techniques to some applications that I already have.
One thing I tried this morning on Windows 7 was to add a jump list to my app. I wanted to add two tasks, and a recent file list. Piece of cake; to be exact, piece of cake without the flour to bake the cake with in the first place. After finding the namespace in Object Browser, I started playing around with the various classes to make the application work but there was no feedback; no jump list, no crash, no error message, Nothing (or null in C#). So I added a handler for JumpItemsRejected event.
The first bit of luck I got was a message telling me that there is no registered handler when I tried to add a JumpPath object. I figured this is because the file type used by my application hasn’t been registered on Windows so I associated this with my program by using Open With in Windows Explorer and tried again; then the weirdness began. I got the same message from my code, there is no registered handler. Meanwhile, I right clicked the task bar button and lo and behold, my JumpPath was right there.
I ran the code again, and again, and again, and again. But this time there was no joy, in place of the JumpPath, I got the message box. I changed the code multiple times to see if anything would change. But the definition of insanity is trying the same thing over and over again, without a Catch block. At this point, I mounted the VS2010 iso and installed the documentation for the first time. When that was done I searched for JumpList and got 33 results which helped me not one bit. It was the same info as what you would find in the Object Browser, no example code. So I went back to the insanity.
I added a task to the JumpList and that worked, only the JumpPath was rejected. All this was in a sample application that opens a .csv file, and the task was calling the same app with an argument of ”-doNothing”. The code in the startup procedure checks for an argument and displays it in a message box,or loads as normal if there is no command line argument. I invoked the task and take a wild guess what I got! The jump list with the JumpPath included.

It’s a conspiracy I tell you. It didn’t take me long to get to the bottom of it, the program that was registered to handle the file type is Jump.exe, the build result. The program that was running when I pressed F5 in the IDE is Jump.vshost32.exe (I am on Windows 7 64 bit). After spending a large part of the morning trying to get rid of the error in my code, I discovered that there wasn’t one; how annoying.
I don’t know if this is a known issue, it it isn’t then it is an unknown issue isn’t it. But I think the documentation for the final version should tell us that you should run the registered application for a Jump path from Windows Explorer or run without debugging from the IDE . This of course is assuming that the application you are writing has been registered with Windows for the file type you want. And something else for my wish list, give us some samples please. This isn’t an issue big enough that we have to try to figure out ourselves in the morning before heading to the office.
If you want to see the VS2010 code for creating Jump Lists, click here. Remember to register the .code file type before running this code (see the sample.code file inside the solution for instructions). Or better yet, run it without registering and have fun trying to figure out what went wrong. Happy coding.
Last week I wrote about PowerTab and how it can be helpful. I went to www.dnrtv.com and saw something about PowerShell so I downloaded it since I have recently taken an interest in it. To my surprise, I then saw PowerTab in action, the guest actually recommended PowerTab.
Granted it is an old show (from 2007), but I think it is good. Anyone like me who never took notice of PowerShell when it first came out will find it valuable. In my case, I downloaded SQL Server 2008 Express and when installing it, it said I needed to get PowerShell. As a result I didn't check out SQL2008 as I kept forgetting to get PowerShell. Then recently at a developer conference, the speaker spoke of many possibilities with PowerShell. And now I'm game.
Been playing around with it and it is really cool. If you want to check out the video I found you can go to dot net rocks tv and there you will see PowerTab in action.
I came across a great add-on for PowerShell, PowerTab which you can find at the power shell guy's site. This provides you with intellisense when accessing the .NET framework in PowerShell. I know that PowerShell in Windows 7 has a script editor, but I haven't used it so I don't know if it has intellisense or not. I will update shrotly in that regard.
If you find yourself writing any scripts that access the .NET framework, or if you occasionally touch the framework from a powershell session, you will find PowerTab useful. Head on over to http://shrinkster.com/1bgc and check out PowerTab.
I wrote some software some time ago that is used by a mining company for maintaining their stores, HR, and monitoring production. I have been discussing with the MD about ways to give him reports in a centralised manner.
Earlier, I had written a reporting app which can be plugged into the main app for his managers, or can run stand-alone for his own use. The problem is, he doesn't need all the reports it serves, and there are now a bunch of mine shafts and offices that he will need information from, since the company has expanded from mining chrome in one town, to mining gold and chrome in different towns. Seeing as he has a lot of work and a number of other concerns I am not involved in, I couldn't place a whole lot of apps on his machine just for reporting when all he wants to do is see some bottom line figures.
While I was thinking of a solution, I happened to attend a conference on Developing for Windows 7 about 2 weeks ago. One demo the speaker gave was on federated search. He searched for a Steve Balmer video and got a bunch of YouTube results right there in the Windows Explorer shell (in a similar format to the picture below) and I thought, whoa! I had been thinking of writing a shell extension for him to use which would go and search for his data from the various sources and he could see them all unified but this demo saved me a lot of time and effort. After the conference I asked how this works, and was told all I have to do is create an .osdx (Open Search Description) file, and Windows can use that as a search provider.
.png)
My main concern was how much code I'd have to write but was happy to hear that I didn't have to re-write a single line of code. The osdx file can specify a service that I have already written that aggregates the data from all the various sites and the results can be displayed in the explorer window.
This is what I am reseraching now, to see how best I can present these results in detail when he finds something he wants info on. I haven't isntalled the Windows 7 beta so this is something I was completely unaware of. For those like me who haven't heard of this, it is a feature that allows you to search multiple locations from within the Windows environment. For instance, if you want to find something on Bing, Youtube and amazon, you select search providers for these locations and type your search once, and you will have your results displayed right in there.
I will be updating you on my findings in the next couple of weeks. In the meantime, here is something that I found on MSDN that I think will be useful for understanding the schema for the osdx file (XML based) and how this works under the hood.
MSDN article for Federated Search
One of the first things I looked for in the DataSet after I moved to .NET was the equivalent of the Filter property of the ADO recordset. I relied on such functionality a lot, and in many cases I still do. It took just a short time for me to find out that you have to access the RowFilter property of the DataSet's DataView. The syntax in both cases was similar, you construct an SQL like string (similar to what would go into the WHERE clause of a SELECT query). So with this, you could get all the rows from a table and then as the user enters some filter criteria, you can narrow the results down to what matches the user's filter.
Before I go into this, I must say it isn’t advisable to get all the rows from every table, you must get only what you need. But there are some cases where it isn’t too expensive to get all the rows, typically for lookup fields (think Account Types, States, Cities etc.), but it could be inefficient to repeatedly go to the database for just what you want. After my first .NET project I started to look for better ways of achieving this, at least ways to do so without relying on a DataTable, DataSet or DataView.
One such way is using Delegates against a method you can find on some of the IEnumerable(Of T)/IEnumerable<T> classes, such as a List. The delegate in question is Predicate(Of T)/Predicate<T>. Anyone who has done some PROLOG before could be thinking, "Hmm, predicates hey?" these are not quite the same thing. The predicate delegate is simple enough; it takes an argument of type T, and returns a Boolean value. Your preferred IEnumerable class will call your method each time it needs to make a comparison when searching for something.
There are two methods I will cover here, the Find() and FindAll() methods. Find will return only one item, the first item in your List that matches your criteria, and FindAll is what you would use when filtering, it returns everything that is a match. Before LINQ came about, and if you weren’t using anonymous methods in C#, you had to write a full method body for this comparison. That is the technique I will show first. Don’t fret if you don’t see your favorite language, my samples are always in both C# and VB, though my articles may have only VB because that is my favorite language.
Full Method Body
Private Function CompareName(ByVal prod As Filter.Common.Product) As Boolean
If MethodNameFilter.Text = "" Then Return True
'do the the filter...
Return prod.ProductName.StartsWith(MethodNameFilter.Text, _ StringComparison.InvariantCultureIgnoreCase)
End Function
The code above is an example of how a VB method that conforms to the Predicate(Of Filter.Common.Product) will look like. In this case, I am looking for products with a name starting with the text inside a textbox named MethodNameFilter. The method is called like so:
filtered = filtered.FindAll(AddressOf CompareName)
In C#, the equivalent code to call the method is slightly different:
filtered = filtered.FindAll(new Predicate<Filter.Common.Product>(CompareName));
VB allows you to write code just like this, where you create an instance of the Predicate<T> for some T, and then specify the method, but it has the convenient syntax of just saying AddressOf and then it will do the rest because it will know what delegate to use, and it can verify the method signature as you type.
By specifying the method in the call to FindAll(), you are telling the List (in this case I used List<T>) to use the specified method to qualify any objects for the new filtered list. I used the variable name filtered to store my copy of the filtered down list, while preserving a copy of the original list in case the user cleared the filter text. Here is a screenshot to show you what it looks like at runtime.

I allow the user to specifying any combination of two filter criteria, Name and Supplier for the Method body, and Name and Category for the Lambda expression tab, and in both cases I then filter the list down to show only what is a match. As you can see from the screenshot, there is an auto complete list for the Supplier textbox. I included code to create that in the attached download to show how you could assist a user. The Category textbox also has one. I've had to do that with info that was not normalised in the database, I get a list of all existing values for a column and then suggest to the user, as they are typing, what values to pick from.
Using a Lambda Expression
Doing the same thing in VB using a lambda expression is like this:
filtered = filtered.FindAll(Function(prod) _
prod.ProductName.StartsWith(LambdaNameFilter.Text, _
StringComparison.InvariantCultureIgnoreCase))
And in C#,
filtered = filtered.FindAll(prod =>
prod.ProductName.StartsWith(LambdaNameFilter.Text,
StringComparison.InvariantCultureIgnoreCase));
In both cases, I use the inference capacities of both compilers to avoid typing a lot of code; you can see an example of how to do so without Local Type Inference in the comments in the attached download.
These lambdas do the same thing as the method body, and they both match the signature of the Predicate(Of T)/Predicate<T> delegate.
Searching for a specific item
The above examples covered how to use this technique to get all matching items. There are times however when you may want to get only one item. The List class comes with a corresponding Find() method that accepts a Predicate(Of T) argument, and then returns a single result of type T. the return value can be Nothing (null in C#) if there is no match, it if there is more than one item satisfying the criteria, the method will return only the first one. The method bodies and lambdas look exactly the same as before, because it is the same type of comparison using the very same Delegate, so I will not include the code here.
Conclusion
The data in this case as you can see from the screenshot is from the Northwind same database. Just in case someone out there has not installed the database, I included an XML file with the data that a shared library (shared between the VB and C# windows applications) reads to construct the list. I read the data using LINQ to XML in VB with the very sexy XML literals. I also included the project that created this XML file and you can run it by right-clicking on it, Selecting debug, and then Start New Instance. It runs, creates the file and loads it in IE, or your default XML viewer. You may have to change your connection string to get from your copy of Northwind.
Other List(Of T) methods that use the Predicate(Of T) delegate are, FindIndex, FindLast, FindLastIndex, RemoveAll and TrueForAll. FindIndex and FindLastIndex return the zero based index of the first or last occurrence of a matching element respectively. FindLast does the opposite of Find; it returns the last matching element in the list. RemoveAll will remove all elements that match the criteria that are matched by the predicate you have specified. And finally the TrueForAll method will return true if all items in the list match the given criteria. It will call the predicate for each element in order and will stop processing the first time false is returned.
Have a look at the attached download project if you wish to see more about how to use this technique in your own code. Hope this helps, and happy coding.
I have spent the last couple of weeks going over an application I wrote 5 years ago, (the one I referred to in my garbage collection blog. There is nothing wrong with this application but I wanted to review some of the decisions I made then in light of what I know now so that I can see how far I've come and how I can make it perform better, because I know I definitely should have learnt enough about performance in the 5 years since to improve on it.
The reason I picked this particular application is that it was my first production application in .NET (started in April 2004, though I'd been using .NET since August/September 2003 – can't quite remember). It turns out that this application was a key stepping stone in my .NET education as I learned quite, not just about .NET. A note that I included in the code there is about patterns. Before starting on this project, I, like many people I still meet, knew very little about design and code patterns. My journey into studying patterns started when after the first release, I was reviewing some of the requirements against how the users used the system.
One particular requirement kept gnawing at me. There was some data that had to be cached for regular access by the users and they didn’t have to wait for it. Customers could walk in and ask random questions and the user's had to be on hand to answer these quickly to serve the next one in line. Different parts of the system itself had to refer to some of this info regularly based on customer activity on the hardware mentioned in the GC blog, and feedback had to be provided to the customer immediately by way of an LCD device.
Following the instructions in the design spec, I loaded this info upfront so that by the time the user was presented with the UI, the data would be available. After the first few days of watching users in different roles interact with this software, I realized that not all roles needed all the information as the spec had said. Also, some of the information could be first required late in the day. This meant that I was loading and holding on to information that may never be used in the context of a particular user. I began thinking about how to deal with this.
Some of this data I stored in simple collections, and the rest in datasets. I used datasets a lot in this application because a lot of the users would need the data displayed in a grid with a mechanism to filter it, and the only way I could filter stuff at in memory without using a refined database search at the time was using a DataView against a dataset/datatable. I re-wrote the custom collections to inherit from a base class that I wrote that served as a cache with a sliding timeout period. The client code would no longer search the database and populate the collections, but would just go to the collections for the info they required.
My client provided telecommunication services to their customers and there was a need to provide international dial codes to allow the customers to make pre-paid calls to different parts of the world. Some roles however did not need this information at all, or would only need it for when making a report, which could be once a week, or once a month. The initial strategy would get the data as soon as the application started in Sub Main (void Main() for C# developers). After a little refactoring, the startup code created empty instances of the collections. This data was then loaded the first time any client code referred to it and for the data that wouldn't be accessed the entire day, the sliding timeout would then be activated at this point, and would be moved forward 10 minutes at each access.
I called this the "Delayed Reading Strategy", and in a discussion with someone from Ukraine I met on a programmer's forum, I described this. He then gave me a link to what is now a vital resource for me, the Microsoft Patterns and Practices team website. I discovered this was known as the lazy-load pattern and through some reading material I found on MSDN, and other places, I learned a lot of patters that I used to improve the performance of this application. The result was that after about two weeks of use, users suddenly experience faster start up time because nothing was loaded until it was first needed. Other applications worked better when this application was running now because it required less memory. Anything it didn’t access or refer to in 10 minutes would be disposed to free the RAM.
There were also two tables whose runtime collections were indeterministic. There was never a time I would need to load all the rows, neither would there be a need to say get me all the rows where such a field was equal to blah. The collections would be created based on user and customer activity against specific rows in the table. The corresponding collection would then build itself by adding any row/object to the internal list whenever it was referred to specifically.
I now do a lot of mentoring to students and interns in some companies and find that a lot of them are unaware of code patterns. One thing I tell them when introducing them is that this is a very easy way, and very important way of reducing the bug-count of an application because you can approach problems in a predictable way. I've seen some weird code over the years to implement things like the singleton pattern, software factories and extensibility, all because the programmers were not aware of design and code patterns.
A year later when I decided to specialize in integrating systems, I started to study integration patterns and there is a good e-book available from the patterns and practices team called Integration Patterns, ISBN 0-7356-1850-X. I found this book very valuable and instrumental flattening my learning curve. If anyone out there hasn't venture into patterns, or hasn't heard of them, head over to the Patterns and Practices team site, or download some of their screencasts and you will be amazed at what you learn. This is a topic on which there is a lot of materials so I will not post examples right now but I am currently finishing off a few articles to post over the next couple of weeks that touch on some basic and some not so basic patterns to get people started on patterns.
Conclusion
In conclusion I will point out what I can do to improve my application. Having been performance conscious even back then, the main thing I can do is to change some of DataSet code to use other structures, like Custom Collections. There are other ways I now know to filter through a collection in .NET without the overhead of hanging on to a DataSet. My next blog will be covering some of these ways, which include using predicates with Lambda Expressions or full blown methods satisfying the Delegate signature against an IEnumerable(Of T)/IEnumerable<T> collection. I will also write about the biggest problem I faced once the service this application was providing became popular and it had a heavy load I couldn't simulate on my development machine. Happy coding.
I recently made contact with a friend I worked with 5 years ago on a project to start a new line of business for an internet cafe. He worked on the specifiec hardware requir4d for this while I wrote the software for the hardware, and the software the client would use to run their new business. The result was that we were both employed by the company to maintain and further develop this system. During this period I began to teachhim to write code in .NET and for some reason I was unsuccessful in explaining the garbage collector to him. No matter what real-world example I used.
On one occasion, we went to a small restaurant
for lunch as we did once a week to discuss the project and other plans we had.
This restaurant was virtually unknown because you had to go into a super
market and up to the second floor to get to it. Once there, you would stand in
line, make an order by the counter, pay, get your food, find a free table, eat
and leave. It was hardly ever full so this model worked quite well.
On this particular occasion however, we found it
packed, and after getting our food we had to wait a few minutes before finding
a free table. As we finished eating, we spoke of some example programs he had
been looking at, one of which explicitly invoked the garbage collector using
GC.Collect(). As I began to explain this, a cleaning lady quickly came and took
our plates and went over to clean them so they could be used for someone else’s
meals.
This was the break I needed. I then explained to
him the GC was much like this cleaning lady. She is there all the time though
we are usually unaware of her presence. We often finish our meals (set
variables to Nothing or null) and leave before she begins her work. On any
given day, we cannot determine at what point she will collect the empty or
abandoned plates from the tables for cleaning.
Someone higher up the food chain may instruct
her to start cleaning (explicitly invoking a collection using GC.Collect) and
we may be there to witness it, or not. When memory availability is low due to
some memory intense process, (restaurant is busy and all plates are in use),
the GC may scramble to reclaim memory used by unreferenced objects to allow
other processes to use the memory without having to hunt for it. This is just
what we had witnessed. Most of the plates were in use. People were sharing
tables (we had two strangers on ours) just to avoid eating on their feet. This wasn’t
helped by the fact that about 20 people were still waiting in line to get their
meals.
Any free plates and tables needed to be
reclaimed as quickly as possible to avoid people having to eat on dirty tables;
I won’t even consider dirty plates. The cleaning lady had to be on hand this
time and kept going round the dining area picking up any empty plates she could,
even if the people were still at the table and she would also clean the tables
as soon as they were freed.
This isn’t the best explanation in the world,
but it was enough to get the concept across to someone who didn’t understand “how
we use” the garbage collector. And I have employed it a number of times since I
encounter a lot of people starting out in .NET who think they have to use the
garbage collector, and wonder when it is best to do so.
The GC is something the .NET runtime will manage
for us and w never have to (at least we hardly ever have to) invoke it ourselves.
It has 3 generations with long running objects occupying the higher generations
which are collected less frequently. When our applications stop executing (are
terminated/unloaded) all the memory they were using is collected. We can also
sometimes submit specific objects ourselves by calling Dispose on IDisposable objects
(restaurant equivalent is handing in our plates at the cleaning sink for
cleaning). I must note that the GC doesn’t dispose these objects, they free any
resources they were using themselves and then tell the GC to ignore them when
collecting dead objects.
I just touched on this subject lightly and if you want a more detailed discussion to the technical aspects, here are a couple of links;
I hope this helps a little more than a few newbies. Happy coding.