Saturday, March 27, 2010

Save Money! Lose Weight! Get A Dog.

We've owned our house for about three years now, and we've been through two real estate tax assessment cycles. For me, that means two assessment appeals - I'm that kind of guy.

The key to a successful appeal is good comps - recent sales of comparable houses in the area. The first year, I didn't have good comps and we lost the appeal. This year, I had solid comps, and we won. The assessment came down $25,000. That'll mean a savings of about $300 on our real estate taxes.

Why did I have better comps this year? Because of Jackson. I walk him around the neighborhood every day, so I see what's for sale. I keep track of the addresses, and, come assessment appeal time, I know where to start. Sure, you can get comps from sites like Zillow, but it's easier when you've previewed the comps yourself. Feet on the ground wins.

Which brings me to the weight loss and exercise benefits of dog ownership. I had been exercise walking for years without losing much weight. Now that I've added an hour of daily Jackson walking to the mix, the weight is coming off. It's a different kind of walking - slower, lots of stops - but it burns calories. I've dropped about 12 pounds in the nine months we've had Jackson, and I'm shaped somewhat less like a transcontinental zeppelin.

So get a dog and your life will be perfect. It's a scientific fact.

Wednesday, March 24, 2010

Using Extension Methods To Refine The SharePoint API

A .Net extension method is a method you add to a class from outside the class. The new method behaves just like an instance method of the class. The technique is different from inheritance - you don't create a subclass, you just add a method to the original class. You don't need the class source, and you can add an extension method to a sealed class. It's so smooth that your extension method shows up in Intellisense just like any other method. If this all sounds a little magical, here's the Microsoft info.
When you're working with someone else's API, extension methods are a powerful tool: hey presto, you have a seat at the table with the API designers. For example, I don't like this common SharePoint idiom for translating a list column display name to the internal name:
string internalName = lst.Fields[displayName].InternalName;
It's messy, and it punctures the list abstraction: I was working with a list, but now I have to deal with the SPFieldCollection within the list. Here's what I'd like instead:
string internalName = lst.InternalName(displayName);
And, with the right extension method, I have it:
static class SPListExt
{
    public static string InternalName(this SPList lst, string displayName)
    {
        return lst.Fields[displayName].InternalName;
    }
}
You can drop a class of extension methods right into a source file, and everything will work. But you're better off separating the class out as a class library. This involves a bunch of plumbing work. Here's a checklist:
  • One-time setup: find "gacutil.exe" on your development machine, and add its directory to your PATH environment variable. If you're in Visual Studio, exit/restart;
  • Sign the library. This makes it GAC-able. Properties » Signing. Check "Sign the assembly". For the strong name key file, use "classname.snk". Don't use a password. After the .snk file is created, drag it to the Properties folder;
  • Add a post-build event:
gacutil -i $(TargetPath)
copy $(TargetPath) "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PublicAssemblies"
This copies the library into the GAC, so that SharePoint can find it. (Caveat: development only! Not the right way for production deployment.) It also copies the library to PublicAssemblies, so that Visual Studio can find it when you add a reference. (If you have multiple Microsoft Visual Studio directories, try the highest-numbered one first.)
    Now you can use your extension methods class in a project like any other library. Fix that API!

    Monday, March 15, 2010

    Logging 101

    I think a decent logging infrastructure is a must-have for software development. So, when I started doing SharePoint work, I searched for the basics. The info's out there, but it's scattered. Here's what I've pulled together.

    Reading The Logs

    SharePoint 2007 writes its logs to the LOGS folder under the 12 Hive. The logs are text files in Unified Logging Service (ULS) format. The file names are servername-yyyymmdd-hhmm.log. The timestamp is the file creation time.

    The first time you look in the LOGS folder, you'll see a lot of logs - probably more than you want on a development machine. Fortunately, you can easily change that. Look at the "Throttle Logging" topic here. My log settings look like this:

    Media_http4bpblogspot_kiamy

    These settings tell SharePoint to give me as much detail as possible about the last hour, and split it across two log files.

    You can read the logs with a text editor, but that's painful. Instead, go to codeplex and search for sharepoint log viewer. You'll find all sorts of freebies. Some are stand-alone; some extend SharePoint's Central Administration site. I'm using the stand-alone SharePoint LogViewer.

    Writing To The Logs

    This works in MOSS 2007, but not in vanilla WSS: first, make sure your project has a reference to Microsoft.Office.Server - in the Add Reference dialog, browse to C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions12ISAPIMicrosoft.Office.Server.dll.

    Then you can use PortalLog.LogString() to write to the SharePoint logs:

    ...
    using Microsoft.Office.Server.Diagnostics;
    ...
    public override void ItemAdded(SPItemEventProperties properties)
    {
       string thisClass = this.GetType().Name;
       PortalLog.LogString(thisClass + ": this works");
       PortalLog.LogString("{0}: this works too", thisClass);
       PortalLog.LogString("{0}: and this {1} works",
           new string[] {thisClass, "also"});
    }
    ...
    

    You can use LogViewer to verify that the logging is working. Starting each message with the class name makes it easy to filter:


    Media_http4bpblogspot_ybdcj


    A couple of caveats:

    Officially, PortalLog.LogString() is Microsoft-internal and "not intended to be used directly from your code." This doesn't seem to be stopping anybody.

    In some cases, you may also want to write to the Windows Event Log, even if this means you're double-logging. Some organizations have automated monitoring software that scans the Event Log. If it notices your SharePoint application error message ASAP, that's a good thing.