# Friday, July 27, 2007

After upgrading DasBlog to the latest release and setting up FeedBurner I felt that I needed to do something to improve my posting experience.  Since inception I've been using the built-in rich text web form in DasBlog.  However good it may be it still lacks in a few areas:

  1. No real-time spell checking.  Since FireFox 2.0 came out this hasn't been an issue since it includes a very nice spell checker.
  2. Code formatting.  For the life of me, I cannot get code formatting to respect my tab spacing.  It parses the code just fine, but after it gets inserted into the post text area all the tabbing is gone.  This last point has really frustrated me and kept me from posting code as often.
  3. No offline mode.  Yeah I know, that's a bit much to ask of a web product, although Google seems to have found away around this with their Google Gears, which allows me to use the Google Reader in offline mode.

All of these issues have led down the path to Windows Live Writer, which is what I'm using right now to write this post.  The thing that amazed me about both DasBlog and Windows Live Writer, is that installing and configuring Windows Live Writer just worked.  There was no oeed to read any instruction manual or otherwise research how to set this up.  It just worked.

The other thing that impressed me was that it has a web preview mode which allows me to actually see this post as would appear on my blog - and I mean exactly as it would appear on my blog.  It basically has a complete cache of my blog home page, even when disconnected from the inter-web, which is really nice and unexpected.  In Google terms, that feature "delighted" me.

As for code, lets see if I can cut and paste from Visual Studio...

/// <summary>
/// Converts a local DateTime instance to the MiniTix date time format.
/// </summary>
/// <remarks>
/// ISO 8601 date format in Zulu time.
/// </remarks>
/// <param name="date">The date.</param>
/// <returns></returns>
public static string ToMiniTixDateTimeFormat(DateTime date)
{
    return date.ToUniversalTime().ToString("u");
}

Darn, that didn't quite work did it?  Fortunately I noticed Windows Live Writer has a plugin feature.  Google search...  Found a code formatter plugin right away on CodePlex!  Lets see how the new plugin works.  Exception, Directory not found!  OK that didn't work, although Live Writer did find and load the plugin automatically while it was running (I unzipped the plugin to the plugins folder while Live Writer was still running), lets try restarting Live Writer and try again - Insert clipboard as code:

/// <summary> /// Converts a local DateTime instance to the MiniTix date time format. /// </summary> /// <remarks> /// ISO 8601 date format in Zulu time. /// </remarks> /// <param name="date">The date.</param> /// <returns></returns> public static string ToMiniTixDateTimeFormat(DateTime date) { return date.ToUniversalTime().ToString("u"); }

 Much better!  Even the XML comments got picked up.  Finally, lets see if I can post!

Friday, July 27, 2007 6:14:49 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
It seems like most of the libraries I use in .NET output log statements via log4net, which is great.  The one thing that often occurs though is information overload, especially when I set my root logger to DEBUG.  Since I follow the logger per class convention, and I name all my loggers based off of type its super easy to allow DEBUG messages for my code, while turning other packages to INFO.

    <root>
      <level value="INFO" />
      <appender-ref ref="ConsoleAppender" />
    </root>
    <logger name="GalleryPlayer">
      <level value="DEBUG"/>
      <appender-ref ref="ConsoleAppender" />
    </logger>

The above lets NHibernate (or whatever else) log at the INFO level, while my code under the GalleryPlayer namespace logs at the DEBUG level.

Friday, July 27, 2007 5:29:09 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
It seems everyone these days is using FeedBurner or some other feed aggregation service, so I finally jumped on the band wagon and setup a feed for this blog @ http://feeds.feedburner.com/sneal.  There were several compelling reasons to do this:

  1. Feed speed optimization, my blog server isn't the hottest thing around - by a long shot.  In fact its on my todo list to find a new hoster.
  2. Exposure, hopefully I can draw in more readers.
  3. Feed analytics.  Right now I have really no idea if anyone ever reads this blog, or how often.
  4. Everyone's doing it.

Friday, July 27, 2007 4:42:33 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [3]  | 
I just finished upgrading my DasBlog software from an older 1.9 release to the latest 1.9 version.  I just copied everything from the new version's zip archive, except for the SiteConfig folder, directly over my blog site.  It seems to have worked just fine, which actually somewhat suprised me.

Wee!

Friday, July 27, 2007 3:17:31 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Thursday, July 26, 2007

Well, I fixed our CC.NET build that builds one of our C++ projects.  The MSBuild script was taking longer than the timeout specified in CC.NET (which was set to 5 minutes), so CC.NET was killing the build before it finished without reporting as to why the build was failing.

Thursday, July 26, 2007 10:26:06 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
This is a note to myself to take a look at Coco-R.

Coco is a compiler compiler (I guess that's where coco comes from). You have probably heard of tools like lex and YACC - Coco-R is a modern version of these tools. What's really great about it is that there are ports to several languages including C#. This is very convenient because additional processing you may want to do during parsing can be written in the same language tool itself is written in - C#.

Thursday, July 26, 2007 5:17:12 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Saturday, July 21, 2007
Sometimes I like to drop databases locally even when I'm connected to them.  This usually comes in handy when I'm rebuilding a DB using a script.

USE MASTER
GO

-- If the database already exists, drop it
IF EXISTS(SELECT * FROM sysdatabases WHERE name='Northwind')
ALTER DATABASE Northwind SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO

IF EXISTS(SELECT * FROM sysdatabases WHERE name='Northwind')
    DROP DATABASE Northwind
GO


Friday, July 20, 2007 11:20:15 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, July 18, 2007
Unfortunately I found myself needing to use an out parameter in a legacy codebase, but couldn't figure out how to get it to work correctly with Rhino Mocks.  It turns out there's a special syntax for that.

From: http://en.wikibooks.org/wiki/How_to_Use_Rhino_Mocks/Out_and_Ref_Parameters

int theRef = 42;
int theOut = 0;
Expect.Call(obj.MyMethod(ref theRef, 0, out theOut)).Return(True).OutRef(13, 666)


Wednesday, July 18, 2007 5:17:16 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Friday, July 06, 2007
So I spent a few hours on the 4th of July learning to use Windows PowerShell.  I was intrigued by the raw power available WMI, COM, and best of all .NET all from a scripting platform made for doing admin like tasks.  The best part is that the interfaces between local disk, UNC paths, and even registry keys are all the same.  So with my new tool in hand, I thought I would give my problem of recursive deletion of "_thumbs" directories another shot.

Get-ChildItem -path c:\temp -filter _thumbs -recurse | Remove-Item

How much simpler is that?!  That's what I wanted to do the first time with the regular windows command shell.  I'm sold, I'm using the Windows CommandShell from here on out - and you should too.

Friday, July 06, 2007 6:42:05 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Sunday, July 01, 2007
I needed to remove about 60 subdirectories named "_thumbs" from my pictures directory.  Of course manually doing this through Explorer wasn't something I was up for.  I tried to do it through the command line, but RD doesn't support multiple directories as inputs.  I wanted to do this:

dir /AD /B /S *_thumbs* | rd /s

but that didn't work, so I had to write my own RD command that is capable of piping input through it - which was still faster than doing it through Explorer.

dir /AD /B /S *_thumbs* | consoleapplication1

using System;
using System.IO;
using log4net;

namespace ConsoleApplication1
{
    class Program
    {
        private static readonly ILog Logger = LogManager.GetLogger(typeof(Program));

        static void Main(string[] args)
        {
            string input;
            do
            {
                input = Console.ReadLine();

                if (input != null)
                    DeleteDir(input);

            } while (input != null);
        }

        private static void DeleteDir(string input)
        {
            if (Directory.Exists(input))
            {
                Logger.InfoFormat("Deleting directory {0}", input);
                Directory.Delete(input, true);
            }
            else
                Logger.WarnFormat("Directory {0} does not exist", input);
        }
    }
}


Sunday, July 01, 2007 4:06:27 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [2]  | 
# Friday, June 29, 2007
There's nothing quite like running your application through the debugger for the first time in a day after 6 hours of coding only to realize the shared dev SQL instance is stopped.  Actually it's quite graitifying to know that I'm making a web page flow change and haven't run a SQL query or fired up IE once all day.  Thankfully my unit test have been giving me good feedback all day long.

+1 point for unit tests.
+1 point for refactoring previously untestable legacy code.
-1 point for sharing the same dev database!  I can't wait to fix that.

Friday, June 29, 2007 10:55:34 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
reg add "\\remotePCName\hklm\system\currentcontrolset\control\terminal server" /f /v fDenyT
SConnections /t REG_DWORD /d 0

Friday, June 29, 2007 4:27:29 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, June 27, 2007
Sometimes you want to share session between web apps, not just between web servers.  By default you cannot do this with the SQL Server session state provider because it keeps differently named applications session's separate.  To allow this, we can modify the TempGetAppID sproc in the ASPState database.  Most solutions I've seen to this just override the sproc and allow ALL web apps using this database to share session, or they are hardcoded to look for specific app names.  Neither of these options was appealing, and worse yet the second option wasn't even viable when using the builtin Visual Studio 2005 web server. 

The solution I came up with was to use the connection string "Application Name" as the appName.  If you are familiar with SQL Profiler you will recognize this.  By default all .NET applications report they have an application name of ".NET SQLClient Data Provider" unless you have overridden it in the connection string.  This allows me to pool sessions between web applications conditionally through a configuration change, that even works on the built-in Visual Studio 2005 web server (webdev.webserver.exe).  Here's the new sproc:

    USE ASPState
GO

ALTER PROCEDURE dbo.TempGetAppID
    @appName tAppName,
    @appId int OUTPUT
AS

    -- start change

    -- Use the application name specified in the connection for the appname if specified
    -- This allows us to share session between sites just by making sure they have the
    -- the same application name in the connection string.
    DECLARE @connStrAppName nvarchar(50)
    SET @connStrAppName = APP_NAME()

    -- .NET SQLClient Data Provider is the default application name for .NET apps
    IF (@connStrAppName <> '.NET SQLClient Data Provider')
        SET @appName = @connStrAppName

    -- end change

SET @appName = LOWER(@appName)
SET @appId = NULL

SELECT @appId = AppId
FROM [ASPState].dbo.ASPStateTempApplications
WHERE AppName = @appName

IF @appId IS NULL BEGIN
BEGIN TRAN

SELECT @appId = AppId
FROM [ASPState].dbo.ASPStateTempApplications WITH (TABLOCKX)
WHERE AppName = @appName

IF @appId IS NULL
BEGIN
EXEC GetHashCode @appName, @appId OUTPUT

INSERT [ASPState].dbo.ASPStateTempApplications
VALUES
(@appId, @appName)

IF @@ERROR = 2627
BEGIN
DECLARE @dupApp tAppName

SELECT @dupApp = RTRIM(AppName)
FROM [ASPState].dbo.ASPStateTempApplications
WHERE AppId = @appId

RAISERROR('SQL session state fatal error: hash-code collision between applications ''%s'' and ''%s''. Please rename the 1st application to resolve the problem.',
18, 1, @appName, @dupApp)
END
END

COMMIT
END

RETURN 0
GO


Wednesday, June 27, 2007 7:34:09 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [5]  |