Archive for the ‘SharePoint’ Category

Debugging Features the Easy Way

Sunday, June 29th, 2008

I once heard an analogy that navigating a submarine was like painting
over all the windows in your car, cracking the window and a attempting
to drive somewhere using only sound.  Since I don’t have a sub handy I can’t speak to the accuracy of that, but sometimes debugging in SharePoint seems only slightly easier.

If you’ve ever created a FeatureReceiver, then you’ve probably also
had it not work.  There’s some code that’ll work right the first time
for you, that never seems to be a custom feature.  When the feature
doesn’t work you either don’t get the result you were expecting, or
worse, Something Bad Happened. Even if you assume that you’ve already got
your development environment set up so you can debug a web part, its
not immediately obvious how to debug that feature that’s causing your
problems.

Well, you’ve come to the right place!  Here’s a couple options to fix
up your broken feature:

Attach to w3wp (aka Its Still SharePoint)

 sshot-159
If you’ve ever (successfully) debugged in SharePoint you are probably familiar with this approach.  Fire up visual studio and attach to the w3wp.exe process and then Activate the feature.  Setting a breakpoint in your FeatureActivated and activating the feature through the web UI works in the debugger like you’d expect, so why not just stick with this approach?  The biggest reason is you can’t do the same thing for FeatureInstalled or FeatureUninstalling.  Since you have to use STSADM for those actions, attaching to w3wp isn’t going to do anything for you.

 

Console/Debug.WriteLine (aka printf forever!)
sshot-162
Bring on that retro flavor!  Liberally sprinkle Console.WriteLine’s in your code and you’ll feel like you’ve been teleported back in time and you are writing a C based console app, or at least like a Response.Write from classic ASP.  Using the WriteLines you can ‘debug’ your code without the use of a debugger and you now have access to Installed and Uninstalling. If you are using stsadm, Console.WriteLine will work fine.  If you are activating via the web, or just don’t like other people to see your debugging messages you can use Debug.WriteLine and view the output with something like DebugView. The downside is you have to use STSADM to do your Installation and Deactivation and don’t really have the option of using a debugger if you wanted to.  You’ll have to be pretty quick to attach to the STSADM process before it finishes (or be on a really slow server).

 

Force the Debugger (aka The Easy Way)

 sshot-157
The previous two options have each been useful but have had some pretty serious caveats to using them for everything, if only there was another way!.  Luckily there is, we can just force the debugger to run.  By putting the line System.Diagnostics.Debugger.Launch(); in our code, it’ll attempt to start the debugger.  This approach will work regardless of if you are using STSADM or the UI.  You’ll be presented with the "Launch Visual Studio" dialog.  If you’ve already got the project open, select your running instance of Visual Studio.  Otherwise open a new instance and browse to find your code.

These options should get you on the right track, and who knows, you might even
start like writing FeatureReceivers…or not.

Finding a SPWeb with one hand behind your back

Saturday, June 14th, 2008

Well, maybe not one hand behind your back, but what if you only have the ID of the web?  I received this question after presenting a session at the Twin Cities SharePoint Camp.  I knew you could grab an SPWeb if you knew its URL using SPSite.OpenWeb, but what if you only had the ID?

Worst case solution would be to recursively go through all the Webs and SubWebs in order to find one with a matching ID.  Another possible, though horrible, approach would be to query the SharePoint database and get the URL from that.  Both of those are pretty bad approaches to what is seemingly a simple problem.

After spending a couple minutes with the SDK I found there was a much cleaner approach available, SPSite.AllWebs.  SPSite has an AllWebs property that has ALL the webs under it, not just the top level ones.  It also has an indexer on it that takes in a guid, giving us our perfect Web by ID scenario.

PowerShell Code:

[system.reflection.assembly]::loadwithpartialname("microsoft.sharepoint")
$site = new-object Microsoft.SharePoint.SPSite("http://mysite/")
$siteid = new guid("22625614-bb87-4cb1-a817-52f8a7366640")
$web = $site.AllWebs[$siteid]
$web.Url

Result: http://mysite/toplevel/secondlevel/YouFoundMe

Success!

Deleting SharePoint Site Alerts

Thursday, April 3rd, 2008

A question came up on the #sharepoint Freenode IRC channel (join us) about how to easily delete all the alerts for a site.  He had come across this post about creating a web part to do exactly what he wanted.  However, since he is an administrator and the post requires creating and deploying a web part it seemed like a lot of extra work. Enter PowerShell.

The solution took the form of a simple 4 line PowerShell script:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
$site = new-object Microsoft.SharePoint.SPSite("http://mydomain.com/someweb")
$web = $site.OpenWeb()
"I'd delete {0} alerts" -f $web.Alerts.Count #Only warns about deleting

If you pasted the code above into your environment (replacing the web URL with your own) it will tell you how many Alerts are associated with the site. If you really want to DELETE all of them, you can add the following line of code:

$web.Alerts|%{$web.Alerts.Delete($_.Id)} #Actually Deletes them!

Since you are already in PowerShell, there are a couple other interesting things you can do. You could filter for only the alerts in a single list:

$web.Alerts|?{$_.ListUrl -like "Documents"} #assumes http://mydomain.com/someweb/documents

Or you could find all the Alerts for a specific user across the web:

$web.Alerts|?{$_.UserId -like "DOMAIN\username"}

But wait, there’s more! If you wanted to see all the alerts for a user across the entire site collection:

$site.AllWebs|select -expand Alerts|?{$_.UserId -like "DOMAIN\username"}

Announcing Minneapolis Office Developer Interest Group (MODIG)

Thursday, February 7th, 2008

A new group is starting up in the Twin Cities for developers on the Office platform. This is a great place to go to learn more about developing for both the Office Servers (Sharepoint) and the Office Clients (Word, Excel, Outlook, …) and to network with people working on similar projects. As is important with all groups, it needs a catchy name. So the obvious choice was ‘Minneapolis Office Developer Interest Group’, or maybe not. At least it shortens to the more-easily-pronounceable MODIG.

As a sort of kickoff for the group, this month’s MNSPUG is on understanding what customizations and development opportunities SharePoint 2007 allows. It’ll provide a high level overview of the sorts of things that can be done on the SharePoint platform.

Our first MODIG meeting will cover creating Solutions and Features in SharePoint, discussing some approaches to use them successfully, and plenty of ways to use them unsuccessfully. The meeting will be held at Microsoft’s office in Bloomington at 5:30pm on Feb 21. We’ve got a temporary MODIG site up right now that will be hosting the updated information for the group.


Update:

Slides
Code

DevConnections - PowerShell for SharePoint Developers

Monday, November 12th, 2007

My final presentation at SharePoint Connections was the one I’d been looking forward to the most.  I’m a big fan of using PowerShell and SharePoint together, it was great to show a crowd some of the thing they could do.  I’d done a couple hour PowerShell presentations (that always seemed to run long) before, but never with SharePoint.  The challenge this time was to do them both together…in an hour.  I was able to get through everything I’d planned and now I have some more detailed content that didn’t fit into the presentation that I can put into some future posts.

The deck is now uploaded, and as promised, you didn’t miss out if you couldn’t write down all my commands.  Nearly all of the commands are here, incorrect statements and all.  I also have my profile, so you can see how I cheated in my other presentations.

I also made a basic PowerShell Types (ps1xml) file to demonstrate the how to extend familiar types to make them easier to work with.  You can grab the file and use it in your own development environment, though I probably wouldn’t rely on it in production quite yet.  Remember to get it started you need to:

Update-TypeData -prepend JustAddCode.Types.ps1xml

DevConnections - Customizing the SharePoint Mobile Experience

Monday, November 12th, 2007

Here is the deck and code I presented at last week’s SharePoint Connections conference in Las Vegas.  The deck stands alone pretty well as an overview to what you can do with SharePoint’s mobile experience.  The code gets much deeper and actually implements a SharePoint aware mobile control that you can put in one of your customized templates, and a custom field with different support for rendering on a mobile device.

While putting this presentation together I looked for other examples of people actively utilizing and customizing SharePoint’s mobile abilities and came up empty.  If you are already doing something mobile with SharePoint or you check out the code and start going down that path, let me know.  I’m interested in seeing who else out there is looking into this stuff.

DevConnections - Advanced Feature Development

Thursday, November 8th, 2007

One session down, two to go.  I got my first DevConnections session under my belt.  One of the things I’ll try to do is turn some of my slides and discussion points into charts/datasheets.  The feature ‘gotchas’ and ActivationDependency restrictions are excellent candidates for this.

As promised, here is the slide deck and code samples.  Enjoy!

Creating SharePoint’s SafeControl Entries in PowerShell

Sunday, July 8th, 2007

Manually adding a new assembly for a WebPart to SharePoint can be a hassle.  I always hate tracking down the various parts of the SafeControl line to add to the web.config.  If you’ve ever done this manually before, you know that the most time consuming part is finding the public key token.  My preferred way had been to use ’sn.exe -T someAssembly.txt’, but in .NET 2.0 sn.exe was no longer included with the default install.  Once again, PowerShell gave me a simple solution:

1
2
3
$assembly = [System.Reflection.Assembly]::LoadFile("c:\temp\TestWebPartLibrary.dll") 
$name = $assembly.GetName() 
"<SafeControl Assembly=""{0}"" Namespace=""{1}"" TypeName=""*""  />" -f $assembly.FullName,$assembly.GetName().Name

 The first line loads a dll into PowerShell and stores the resulting System.Reflection.Assembly in a variable.  The next line stores the results of Assembly.GetName() into a local variable we can use later.  The final line similar to String.Format in .NET.  $assembly.FullName outputs the entire value for Assembly we need, including that pesky public key token!  For the Namespace attribute, I’m just using the name of the assembly.  This isn’t necessarily true in all cases, but I usually have the dll and namespace sharing the same name.

When running these three lines I get the following familiar result:

<SafeControl Assembly="TestWebPartLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=82a1533dcdde9e6a" Namespace="TestWebPartLibrary" TypeName="*"  />

Since we’re now able to create the line for a single .dll, lets wrap it up in a function so we can get a bit more mileage out of it.

function get-safecontrolline($assemblyLocation) 
{    
   $assembly = [System.Reflection.Assembly]::LoadFile($assemblyLocation)    
   $name = $assembly.GetName()        
   "<SafeControl Assembly=""{0}"" Namespace=""{1}"" TypeName=""*""  />" -f $assembly.FullName,$assembly.GetName().Name 
}

Now we can call it and pass in the file as an argument. Now its a snap to generate the SafeControl entries for an entire directory!

C:Temp > dir *.dll|%{get-safecontrolline($_) }
<SafeControl Assembly="TestWebPartLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=82a1533dcdde9e6a" Namespace="TestWebPartLibrary" TypeName="*"  />
<SafeControl Assembly="AnotherLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=82a1533dcdde9e6a" Namespace="AnotherLibrary" TypeName="*"  />        

C:Temp >