SharePointy Objects

A developer's blog.

Tuesday, March 23, 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!

Sunday, March 14, 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:


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 Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI\Microsoft.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:





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.