There is a great tool I am sure most ASP.NET and ASP.NET MVC developers are using called MiniProfiler. If you are not using it - I highly recommend getting it installed today, even if just in your development environment (although I always have it running in test and production but restrict access to developers and some trusted power users).
I have recently found the need to write some background processes running as console applications on schedules. Being a background process and not halting any user input, you might ask why I care about profiling these processes. The reason is they get installed on servers along with other critical applications, and if they are constantly churning away in the background, taking up CPU and RAM or chewing up SQL resources, then I believe that will make a noticeable different to the client facing applications somewhere along the line. So it is worth investing the time to make sure they perform OK at least, if not well.
There is no great equivalent I have found for MiniProfiler for the Console/Windows/WPF application environment. But there is no reason you can't actually use MiniProfiler in this environment either!
What about MiniProfiler in non-web environments?It took a bit of mucking around to get this working, so to save time in future I have created a NuGet package called "MiniProfiler.Windows" which helps get up and running a lot quicker. See the page project page at http://nootn.github.com/MiniProfiler.Windows/ for a "quickstart" guide.
While this process makes it easy to implement MiniProfiler around your code and get a nice formatted output for writing to the console, debug window or log files, it is worth spending the time designing your console application for ease of unit testing and performance profiling. I found the combination of IOC and AOP great for this. Your IOC container supports testable, clean code while AOP supports wrapping MiniProfiler steps around relevant methods, without having to litter your method body with profiling code.
There is a demonstration of this in the Git repository for MiniProfiler.Windows. If you fork or download the code, run the "ConsoleApplicationWithIocAndAop" console application for an example, or follow the steps below to get started yourself.
These steps make the assumption you will use AutoFac for IOC and Snap for AOP. You may substitute these for your favorite IOC and AOP frameworks.
a) First, create a new console application. Ensure you change the target framework to ".NET Framework 4" (not client profile)
b) Next, Install NuGet packages "MiniProfiler.Windows" and "Snap.Autofac" (NOTE: at the time of writing this, the Snap.Autofac library had a broken reference to the "fasterflect" library - it was a bit of mucking around to get that working, basically reverting fasterflect back to version 2.0.2 using a manually added reference)
c) Now, into the code! You need to register a few things with your IOC container, and if using Snap, also configure some attributes and how they are handled, for example:
There are a couple of key classes here, "ProfileMethodAttribute" is the attribute you put above any method you want to wrap a MiniProfiler step around:
There are a couple of key classes here, "ProfileMethodInterceptor" is the class that does the work to wrap the method call with a MiniProfiler step, using the method name as the step name d) Any method that you would like a MiniProfiler step wrapped around, you just need to add a [ProfileMethod] attribute to, and assuming that class was provided by the IOC container, it will just work.
e) Finally you can write the main program code. All it should do is start MiniProfiler, run your application logic then stop profiling and get the output:
For the full code example, browse the source at https://github.com/nootn/MiniProfiler.Windows/tree/master/ConsoleApplicationWithIocAndAop.
I hope this gives you some thoughts on how to improve how you write console applications. If anyone would like to provide a code review on the code I have written I would love to know if there is anything wrong or anything that can be improved, please leave a comment or fork me on github!