MOSS MVP

I've moved my blog to http://blog.falchionconsulting.com!. Please update your links. This blog is no longer in use--you can find all posts and comments at my new blog; I will no longer be posting to this site and comments have been disabled.

Sunday, March 22, 2009

New Issue with STSADM MergeContentDB

I just saw this post on the SharePoint forums: http://social.msdn.microsoft.com/Forums/en-US/sharepointgeneral/thread/e9cd9836-5a50-42b3-bf2f-02338a3168f3 – it appears that there’s a possibility for data corruption when using the STSADM mergecontentdb command.  The post details a few things you can do to reduce the possibility of corruption when using the command but it would appear that the hidden message is to use Backup/Restore until a fix is released.

Saturday, March 21, 2009

Why I don’t use OpenWeb()

This has come up in various conversations recently so I figured I’d write up a short post about it.  When trying to obtain an SPWeb object there are a couple of different options available using members of an SPSite instance.  The first, and more common, is the OpenWeb() method and the second is using the AllWebs[] property collection.  Here’s the problem I have with OpenWeb() (specifically the overload that takes no arguments) – consider the following code:

string url = "http://portal/sites/ActualSite/ChildWeb/GrandChildWeb";
using (SPSite site = new SPSite(url))
using (SPWeb web = site.OpenWeb())
{
    ...
}

In the above code if both ChildWeb and GrandChildWeb actually exist then the OpenWeb() call will return the GrandChild web.  However, lets assume that GrandChildWeb doesn’t exist (or perhaps it was spelled incorrectly), in that case what you will get for the web variable will be ChildWeb (assuming it exists).  The problem is that the user will not get any error indicating that the URL provided was invalid – it simply returns back the first valid web in the URL hierarchy.  In some cases this is exactly what you want (this is common when the URL you have is that of a List or Folder) but generally this is not going to be the case.

Now consider the following code where “Utilities.GetServerRelativeUrl” is a helper method that returns back the server relative URL:

string url = "http://portal/sites/ActualSite/ChildWeb/GrandChildWeb";
using (SPSite site = new SPSite(url))
using (SPWeb web = site.OpenWeb(Utilities.GetServerRelativeUrl(url), true))
{
    ...
}

In the above code if GrandChildWeb does not exist then an ArgumentException will be thrown thus ensuring that the code does not now inadvertently operate on the wrong SPWeb object.  Alternatively you could do the exact same thing using the AllWebs property collection as shown below:

string url = "http://portal/sites/ActualSite/ChildWeb/GrandChildWeb";
using (SPSite site = new SPSite(url))
using (SPWeb web = site.AllWebs[Utilities.GetServerRelativeUrl(url)])
{
    ...
}

I actually prefer using this method when the URL I have is explicitly expected to be the URL of a web.  This helps me during code reviews to do a quick search for all OpenWeb calls thus allowing me to focus my attention on how and where the URL parameter is coming from (so I use OpenWeb() with no arguments whenever I have an arbitrary URL that points to a resource below a web and not the web itself and I use AllWebs for everything else).

So I know what you’re thinking: “But Gary, won’t using a property collection result in all the webs being opened so isn’t using AllWebs less performant?”.  Actually, no, that’s not how AllWebs works – internally the indexer for AllWebs makes a call to the SPSite.OpenWeb(string, bool) method passing in the server relative URL and true to ensure an exact match.  This results in an ArgumentException if the URL specified does not correspond to a web.

In conclusion, use AllWebs when the URL you have is expected to correspond to a web and use OpenWeb when the URL corresponds to a list, folder, or file.

Saturday, March 7, 2009

MVP Summit 2009

I had an absolutely great time at the MVP Summit this year.  It was great being able to sit with the product teams and see all the absolutely spectacular stuff that they’ve been working on.  I’m truly excited to start working with it and I know my customers are going to love the new features.  There’s a few things here and there that I hope gets changed before RTM but in the grand scheme of what has been done it’s all pretty minor stuff – the product teams have really been doing an excellent job based on where I was sitting.

Even if I couldn’t see all the great new O14 stuff all the social activities would have made the trip worth it – hanging out with all the super stars of the SharePoint world was awesome (and humbling).  Paintball was a blast, as usual – having a wooded forest to play in added a nice new element to it but speedball was still my favorite part of the day (all that Gears of War I’ve been playing appeared to have helped me out this year :) ).  I can’t wait for the SPC in October when I’ll get a chance to catch up with everyone again.  To all the MVPs – it was great spending time with all of you and I’ll see you in October!

PaintBall

Thursday, March 5, 2009

Follow Me On Twitter

I was having dinner the other night with lots of super star SharePoint MVPs where I ended up sitting next to Joel Oleson, Todd Baginski and Jason Medero – it wasn’t long and the subject of Twitter came up.  Todd had just signed up the night before so I was able to get some insight from those who have been using it for quite some time as well as someone like Todd who just made the plunge.  I’d been considering doing the twitter thing but just hadn’t made the commitment to do it – well, after talking to them I decided to go ahead and get myself setup: http://twitter.com/glapointe

I figure I’ll mainly use it as a micro-blog for the stuff I’m doing – for example, I often push out builds to my extensions but don’t write a blog post explaining what changed as it’s usually just minor bug fixes, enhancements, or tweaks.  So if you use my stuff you definitely want to follow me so that you can stay more up to date on the changes that I make.

Happy Twittering :)

Deleting Orphaned Event Receivers using PowerShell

While looking through the event logs at a client of mine the other day I came across an odd error that was occurring regularly.  Apparently they had developed a Feature which contained an Event Receiver which was programmatically bound to a series of lists.  As time went on their requirements changed so they deleted the event receiver class.  Problem was that the binding to the lists still exists so every time an item was updated an error would be dumped to the event log about a missing type in the specified assembly.

Fortunately it’s pretty easy to fix this using some simple PowerShell:

$site = get-spsite -url http://portal
foreach ($web in $site.AllWebs) {
    $lists = $web.Lists | where {$_.EventReceivers.Count -gt 0}
    foreach ($list in $lists) {
        $evts = $list.EventReceivers | where {$_.Class -eq MyCompany.SharePoint.MyFeature.EventReceivers.MyEventReceiver"}
        if ($evts.Count -gt 0) {
            foreach ($evt in $evts) {
                Write-Host("Deleting..." + $list.RootFolder.ServerRelativeUrl + ", " + $evt.Type)
                $evt.Delete()
            }
        }
    }
}

The only thing that threw me off when I was putting this little snippet together was the fact that I couldn’t work with the collections directly due to errors about the collection being modified during the enumeration (so a “for” loop rather than a “foreach” loop would have worked just as easily as doing filtering as I am above).

The code above is great for when you know the class name of a specific event receiver that needs to be pulled.  If you don’t know the name then you’ll have to add in some reflection to look for the assembly and type – just be careful as the assembly may or may not be in the GAC.