Skip to main content Home Help (new window) Eric Shupps
Go Search
Home
Blogs
Company
Products
Services
Current News
Idera Acquires Sonar from BinaryWave
BinaryWave Announces SharePoint Performance Optimization Service
Upcoming Events
Home > Blogs > Eric Shupps



The new home of The SharingPoint blog.  Refer to the previous URL(http://sharingpoint.blogspot.com) for older posts.

TechEd North America 2010 Wrap Up

Another TechEd done and dusted and what a great one it was. I enjoy New Orleans so having it there was a lot of fun (except the heat and humidity – that was a bit rough). There was a ton (or tonne, for my UK mates) of 2010 content. I didn't get to see many sessions but I talked to a bunch of people who came by the Office TLC and it seems they were all very pleased by the presentations. SharePoint was definitely the belle of the ball once again, with more SharePoint-related vendors in the Expo hall than you could shake a stick at. Having the TLC's and vendors all in the same area was a great move – I hope they stick with that format in the future.

'Nawlins really rolled out the red carpet for all of us (there were several very, ah, "interesting" advertisements from proprietors up and down Bourbon Street catering to the Microsoft crowd). As always, the food was great (except at the conference itself but that always seems to be the case) and the Hurricanes were dee-licious. I'm especially thankful for the gelati vendor in the conference center – they kept me going in the heat. Whoever they were, they should get a key to the city. The only real bummer was that Rob Foster and I couldn't find any big buckets of steamed crawfish to gorge ourselves upon – I do love me some crawdaddies.

Massive props go to the AvePoint team for throwing the best party of the conference in celebration of their DocAve 5.5 release. In a stroke of pure marketing genius, my buddy Tony Lanni managed to somehow arrange for a brass band to lead a couple hundred of us technogeeks through the French Quarter, complete with a police escort and red beads flying in every direction. Tourists were thoroughly confused, lining up Bourbon Street to take pictures and gawk at the scene. It was complete pandemonium. And seeing Mike Watson ride the mechanical bull at the Bourbon Cowboy afterwards – that was priceless.

One of the highlights of the conference that I will remember forever is watching the Chicago Blackhawks win the Stanley Cup with fellow MVP's Andrew Connell and Paul Schaeflein. I know it sounds a bit strange for a Texas redneck to be a hockey fan but I'm a huge NHL junkie (too bad my Stars didn't make it to the playoffs). I have relatives in Chicago and watching them win the cup was priceless (and made so much sweeter by watching that big crybaby Jeremy Roenick sob on national television – oh, the irony). Job well done, 'hawks – you deserved it.

I also got to spend some time hanging out with a few of my favorite non-SharePoint folks – crazy man Alan Stevens, the always beautiful and engaging Amanda Laucher, and party animal Steve Andrews. Y'all rock!

For those who attended my talk on SharePoint 2010 development, the slides and sample code have been posted to my Presentations area here. Also, for those who asked about customizing deployment in Visual Studio 2010, you can find that code here.

Next year, we'll all be storming into Atlanta to geek up the South a bit more. I'm looking forward to it. See you in 2011!

SharePoint Saturday Ozarks 2010

My good buddy Mark Rackley is hosting the 2nd annual SharePoint Saturday Ozarks event in Harrison, Arkansas on June 12 – 13. Unfortunately, I won't be able to make it this year (a fact which I'm sure the Hotel Seville is thankful for as their stock of Corona may last more than a few hours this time). Mark does a great job and has a fantastic lineup of speakers scheduled. If you're anywhere in the Oklahoma/Arkansas/Missouri area, I highly encourage you to attend. It's free and there will be plenty of 2010 content to feast on. Space is limited, so get goin' and make those reservations!

I’ll Be Speaking at TechEd 2010 in New Orleans

It's that time of year again – time for TechEd North America. This year's event is being held in the Big Easy, one of my favorite cities, and is sure to be a winner (how can you go wrong in 'nawlins?). There's sure to be a ton of good SharePoint 2010 content. I have one session on 2010 development targeted towards .NET developers looking to jump onto the SharePoint bandwagon. Here's the details:

Title: Microsoft SharePoint Server 2010 for the Microsoft ASP.NET Developer
Date and Time: Wednesday, June 9th at 1:30PM
Description: SharePoint is the development platform that many developers with ASP.NET background are moving to. Because SharePoint is entirely built on ASP.NET it is a natural way to get access to higher level features. This session outlines the areas that an ASP.NET developer needs to learn to get used to developing for SharePoint. During the talk, see various ways that existing ASP.NET code can be migrated to SharePoint, and demos focused on migrating commonly used ASP.NET project templates.

As usual, I'll be hanging around the SharePoint kiosk during the event so feel free to drop by and say "Howdy!". Bring your toughest SharePoint development questions so I can hand them off to some IT Pro and watch them sweat (just kidding).

See you in New Orleans!

 

SharePoint Evolution 2010 – The Conference That Almost Wasn’t

We just wrapped up the SharePoint Evolution 2010 conference in London. By all accounts, it was a great event. Attendance was excellent and there was a ton of new content on SharePoint 2010. The Combined Knowledge crew made everything appear smooth and effortless. But things are not always as they seem – this conference was perhaps one of the most difficult conferences to put on that I've ever been involved with. Just to give you a taste of what happens in the background when things go terribly wrong, I thought I'd give a behind-the-scenes account of the insane amount of effort that went into this event.

My personal travel journey sets the stage for one of the strangest logistical nightmares ever encountered for a conference of any type. On Wednesday, the 14th of April, I was schedule to fly to London on the last direct flight of the day out of D/FW airport. About the time they were boarding business class, the gate agent made an announcement that a volcano in Iceland, of all bloody places, was delaying our departure. She wasn't sure if we were going to be allowed to leave. As you can imagine, everybody just looked at each other as if this was some strange sort of joke. I mean, really, a volcano in Iceland? Who cares? What possible impact could that have on a flight to England? That's like, all the way at the top of the world, right? Somebody must be putting us on.

Sadly, as the whole world now knows, it was no joke. Amidst all the grumbling, cursing and general carrying on, the agent came back on in a few minutes and told us we could just make it if we moved now. Fast. As in, get yer butts on the plane and don't dilly dally around. We still had no idea of what she was going on about but if we could make the trip then fine, let's get going. I travel nearly 80,000 miles a year in the air, almost all of it on American Airlines. I have never, ever, seen a flight crew move so fast. They had every seat filled and doors closed in less than fifteen minutes. Five minutes later we were on the tarmac. The pilot came on and gave us a run down of the situation. Heathrow airport was predicting they were going to close ALL air traffic by noon the following day. We were due to arrive at 12:25. If he put the afterburners on we just might make it. So get in, sit down, shut up and hang on (that's not actually what he said but I'm not paraphrasing by much – he was definitely a good ol' country boy in a city slicker hurry).

Naturally, we all had a good chuckle for the next nine hours. Close Heathrow airport – right, as if that would ever happen. It's the busiest airport in the whole freakin' world. Every few hours the pilot would come on and update us, each time assuring us that we were ahead of schedule and were going to make our gate, volcano be damned. "Step on it!" someone yelled at one point. I couldn't resist – I looked at the guy next to me and said "Boogity, boogity, boogity!" but, since he was British, he didn't get it (that's a NASCAR reference, for all of you who don't follow real racing). As it turns out, we were wheels down at 12:11 and at the gate by 12:20 – ten minutes before they shut the whole place down. Done. No more planes, no way Jose. I'll spare you the details of what Heathrow was like that day – if you've ever been through there, imagine it on its worst day then multiply that by at least ten. It was a complete zoo. All I can say is thank goodness for IRIS or I would have been waiting in customs for days.

So I had snuck in the country just in time. Now what? Well, once we were able to catch up on the news, we all thought things would be back to normal in a day or two. Not so. Thursday became Friday, Friday turned into Saturday, still no flights. Now we had a real problem. Out of all the speakers scheduled to appear at the SP Evolution conference, nearly half of them were from out of the country, and most of those were from the US. That meant we had more than 75 sessions to deliver and were short nearly half our presenters. Uh oh. That's what you call a serious logistical problem (or a SNAFU, if you were ever in the military). I rang up Steve Smith and offered to jump on the first train to London from our offices in the West Midlands to help him figure out how to handle the mess we found ourselves in. Once I arrived, I found Steve and Chandima, who had just made it in on the Eurostar from Paris after travelling from his home in New Zealand, ensconced in a boardroom we quickly dubbed the "battle room". Over the next five or six hours, we played musical sessions, with Steve scribbling a session title and presenter on the whiteboard, then erasing and moving it around each time an update came in announcing that yet another speaker was stranded. With Outlook up on one computer, Twitter up on the projector, and Steve's iPhone going off every ten seconds, we were in a barely controlled state of chaos. We would look at the schedule, check our list of cancellations, make frantic calls to see if someone who was scheduled for Tuesday or Wednesday could get there on Monday, write on the whiteboard, erase it, move things around, and repeat the cycle. By 9PM we still didn't have a full schedule for Monday and it was starting to look grim.

But then a funny thing happened. Calls started to come in from local UK people who only had one session scheduled saying they would be happy to do another. Microsoft folks who didn't originally plan to participate chimed in to volunteer, some of whom even had presentations already prepared. Community participants who hadn't done much public speaking offered to take a session, any session, if that would help keep things on track. Stranded speakers started emailing their decks and demos in case somebody else could deliver their session. Tobias Zimmergren, who lives in Malmo, Sweden, emailed to say that he was getting in a car and driving to London, offering to pick up anyone who might be on his route (that's a 1700km journey and nearly 22 hours of windshield time). Daniel Wessels hopped on a train in München, Germany, facing lord only knows how many connections and sardine-like conditions. Other speakers were reporting similar travel insanity but were bound and determined to get to London come hell or high water. Within an hour, we had the schedule for Monday sorted. And it even looked like Tuesday might come together if everyone who said they could be there actually made it.

On Sunday, speakers started to arrive in force, and the battle room swelled to a dozen people. Steve and several others attacked the schedule for Tuesday, and everyone began working on sessions for the following day. In case you've never done one before, it's safe to say that an hour's worth of content, including slides and demos, usually takes more than ten hours to prepare, and sometimes considerably longer. Several speakers who were originally scheduled for Tuesday or Wednesday had planned to prep their content during the week but had now been moved to first thing Monday morning. Some picked up sessions with content they were unfamiliar with or had never worked with before (bear in mind this is a new product version with tons of new features – none of us has had a chance to look at everything, much less work with it enough to talk intelligently in more than a couple of areas). I was dumb enough to volunteer for the first developer session on Monday. How do I get talked into these things?

The original plan for the Keynote presentation was to have myself, Steve, Spencer Harbar, Andrew Connell, Bill English, Penny Coventry and Todd Bleeker do a "how we got here" roadmap, starting with SharePoint 2001 and moving through CMS, SharePoint 2003 and SharePoint 2007. With Andrew stuck in Oslo, Norway and Bill and Todd never able to make it out of the US, that presented a bit of a problem, especially as everyone had their own version of old images to work from (how anyone got 2001 up and running at this stage is beyond me). Thankfully, Brett Lonsdale stepped in to take over the 2003 developer piece, Spence covered AC's bit and we pulled it together. With not a single minute of rehearsal, we managed to get all the machines running on stage at once and the keynote came off without a hitch. That could easily have gone very wrong in front of the whole crowd.

By Tuesday, things were humming along. After way too much fun the night before trying to let off some tension, Andrew Woodward and I managed to get through a ton of content in our unit testing session, working with different versions of R&D code that only a few people on the planet have ever even used. Andrew got a last-minute lifeline from the Microsoftie who actually wrote the core PEX/Moles/Behaviors code in order to get his demo working and, miraculously, I was able to live-code working unit tests with Moles. This sort of thing is kind of like being a test pilot for fighter aircraft; there's a ton of danger and never more than a 50% chance it's going to work - you could easily go down in flames (to be honest, I don't think either one of us had as much as 50% confidence in our demos). Dual presentations are hard to get right without much practice time and, naturally, we didn't have any, but lucky for us Woody and I have bantered about this stuff for at least a year and were able to get through it without looking like complete fools (or so I believe). I got in a couple of digs about TDD and TypeMock, Woody got me on a few points regarding proper isolation and the whole "fail first" thing, and we generally had a good time. My only regret is that we didn't play the video of Woody snoring at last year's MVP Summit (sorry mate, had to get that in J).

Apparently, at some point Monday night, Steve came to the conclusion that it would be a great idea for Ben Robb and myself to do a session on the Client Object Model Tuesday afternoon. I thought he was just poking fun at us and forgot it ever happened. Unfortunately, he was serious and posted it to the schedule without either of us knowing about it. Until Tuesday morning, that is, right before we both went on stage at 10AM. Back in the speaker room after our sessions, we had a genuine "Holy Crap!" moment. We had no slides, no demos, and four hours to put a session together. And we were both dead tired and mind numb. With a lifeline from Spence for slides and the good fortune of having a bit of client OM code hanging around, not to mention a clutch save by Woody on the javascript piece of the stack, we managed to cobble a full session and demos together in less than two hours. It wasn't pretty but it worked. The funny bit was that neither Ben nor myself had actually written live Client OM code before the conference. All I knew about it was what I'd seen in demos and discussed with other MVP's and the product team. The next two hours I spent researching everything I could so I didn't say anything deliberately stupid on stage (randomly stupid I'm OK with – that's part of my normal session content). Again, with no practice time, we hit the stage, wrote our code live on the spot, and it all compiled and worked. That was about as close to a minor miracle as you can get.

By Wednesday, we could all see the finish line. I don't know how many sessions Spence ended up doing (I think six was the final count) but every time I turned around he was on stage somewhere. Steve managed to do an hour of live install and configuration without so much as a script to work from. Several people presented someone else's deck without having any clue what was in it. I don't think anybody did less than twice the number of sessions they originally had planned and several who weren't even on the original schedule delivered more than one. By the time we got to the Ask The Experts panels at the end, we were all completely knackered. One last meal and a few drinks with the folks who stayed in town and SP Evolution 2010 was done and dusted.

It's often said that when times are tough you find out who your friends are. It's a credit to Steve and his crew at Combined Knowledge that they have a lot of really good friends. When the SharePoint community wants to make something happen, we make it happen, period. There was just no way we were going to let this thing go off the rails. We managed to have content in every single slot of five tracks for three full days without missing a single one. I can't say enough about the dedication and perseverance of everyone who stepped up to the plate. Zoe Watson, rock star that she is and the real reason we ever had any chance of getting through it, deserves so many accolades I don't even know where to begin. And the attendees, many of whom had their own challenges, deserve a lot of credit of making it to the show and putting up with a constantly changing schedule. I'm sure some were disappointed that they didn't get to see a particular speaker or session that they had been hoping for but everyone I talked to was positive and grateful for all the effort. It was one wild ride that turned out better at the end than we thought it would at the beginning. As the saying goes, all's well that ends well.

So there's a bit of background on how we managed to make a conference work in spite of a silly thing like a volcano going off at the top of the world. Now, assuming I can actually get back to the States on schedule, it would really be nice to find some deserted beach somewhere and unplug from the world. What are the odds, d'ya think???

 

Jousting with XML - Adding Attributes to Existing Nodes

This isn't technically a SharePoint-related post as the issue is one of pure XML manipulation but I ran across it while building a custom solution in SharePoint and it took hours to figure it out so I thought it merited some attention. When working with XML, as is often the case in SharePoint (especially when using web services), there is often a need to modify some fragment of XML to support a resultant operation. In this particular instance, I had an XML fragment similar to the following:

<Books>
<Book name="My Book" id="book1">
<Chapters>
<Chapter name="Chapter 1" />
<Chapter name="Chapter 2" />
<Chapter name="Chapter 3" />
</Chapters>
</Book>
</Books>

In order to populate a TreeView and from there construct a link for each node with the proper parameters, I needed to add the ID of the parent Book object to each one of the Chapter nodes as a new attribute. Sounds simple enough. I started with something like this (error trapping and null checks omitted for brevity):

 

XmlDocument doc = new XmlDocument();
doc.LoadXml(booksxml);
XmlNode bookNode = doc.DocumentElement.SelectSingleNode("Book");
string bookId = bookNode.Attributes["id"].Value;

XmlAttribute parentBookId = doc.CreateAttribute("bookid");
parentBookId.Value = bookId;

XmlNodeList chapterNodes = bookNode.SelectNodes("Chapters/Chapter");

foreach (XmlNode chapterNode in chapterNodes)
{
   chapterNode.Attributes.Append(parentBookId);
}


Easy, right? Not so fast. Under no circumstances would the new "bookid" attribute get added to each Chapter node in the resultant XML string. I tried all kinds of things, including converting the node to an XmlElement and using the SetAttribute() method, moving the value assignment into the node itself, and so on, but nothing seemed to work. For whatever reason it just ignored my new attribute and moved right along. What was really frustrating was that in debug mode I could see the new attribute being added to each node as I stepped through it. But when the code ran the final output was unchanged.

After much searching around and cursing XML in general, I tried what seemed a silly bit of code:

 

XmlDocument doc = new XmlDocument();
doc.LoadXml(booksxml);
XmlNode bookNode = doc.DocumentElement.SelectSingleNode("Book");
string bookId = bookNode.Attributes["id"].Value;

XmlNodeList chapterNodes = bookNode.SelectNodes("Chapters/Chapter");

foreach (XmlNode chapterNode in chapterNodes)
{
   XmlAttribute parentBookId = chapterNode.OwnerDocument.CreateAttribute("bookid");
   parentBookId.Value = bookId;
   chapterNode.Attributes.Append(parentBookId);
}


Voila! It worked. Moving the creation of the new attribute element into the context of the current node did the trick. That's a bit cumbersome, to say the least, especially as my actual code contained several nested collections of child nodes, so I had to repeat the process for each node in the subsequent collections, each time changing the variable name of the new attribute but leaving the actual attribute name ("bookid") the same. I've since tested it in several variations (.NET Framework 3.5) and found that this is the only method that seems to work. My final XML looked just like I wanted it to:

<Books>
<Book name="My Book" id="book1">
<Chapters>
<Chapter name="Chapter 1" bookid="book1" />
<Chapter name="Chapter 2" bookid="book1" />
<Chapter name="Chapter 3" bookid="book1" />
</Chapters>
</Book>
</Books>

I'd love to know what's going on here. Why is a globally declared (in the context of the XML document itself) attribute not viable while a locally declared (for each node) attribute that's created in the context of the parent document perfectly feasible? It sure makes for some ugly code and the test routines aren't very clean. If anyone has some insight to share please enlighten me. On the other hand, for once it wasn't some weird SharePoint-only thing, so I guess I should be thankful for that…

 

 

 

 

 

SharePoint Evolution Conference in London April 2010

We're now only a couple of months away from the upcoming SharePoint Evolution 2010 conference in London, England. Last year's Best Practices event was one of the best conferences I've ever attended or spoke at. The venue is fantastic – right across from the Houses of Parliament and Westminster Abbey. The Combined Knowledge crew does a great job of organization and production. Best of all, there's tons of content from speakers who come from every corner of the globe.

I'll be presenting two sessions at the conference. The first, Customizing the Visual Studio 2010 SharePoint Deployment Process, is a repeat of my talk at SharePoint Conference 2009. The second, Unit Testing SharePoint, is a highly anticipated slugfest on Unit Testing between myself and the always-entertaining Andrew Woodward. I'm teasing a bit – Woody and I are good friends and share a lot of the same views on Unit Testing (as in, do it, no matter which camp you're in). It's going to be a lot of fun to share the stage with Woody and banter about SharePoint testing. Believe me, you don't want to miss this one!

As with last year, I will be conducting an unofficial "Redneck Tour of London" for all the US folks who've never been to London before (and anyone else who wants to tag along). As my adopted second home city, I'm pretty familiar with all the tourist spots in London, along with a few off-the-beaten-path locations that most folks never get to see. We'll be doing some of the standard attractions, including Parliament, Westminster Abbey, Buckingham Palace, The Tower of London, St. Paul's Cathedral, Horse Guard's Parade, Tower Bridge, Trafalgar Square, and the like, but we'll also branch out and do some other fun stuff, like the Jack the Ripper Ghost Walk, the HMS Belfast, Covent Garden, Shakespeare's Globe Theater, Benjamin Franklin House and the London Dungeon. Or anywhere else we all feel like going on a whim. Not to mention all the pubs and restaurants I'm well acquainted with J It'll be two full days of fun in London after the conference, so if you're planning on coming over be sure to stay through the end of the week. Trust me, nothing is quite so entertaining as watching a gaggle of tourists follow a redneck in big black hat around town. It's worth coming along just to watch the locals react!

Be sure to hit the conference site and register if you plan on attending. This event WILL sell out and you don't want to miss it.

See you in London!

SharePoint 2010 Code Deployment, Part Three

Part One of this series gave a general overview of SharePoint 2010 code deployment using Visual Studio 2010. Part Two described the creation and use of SharePoint Commands. In this installment we will explore SharePoint Deployment Steps and their relationship with both SharePoint Commands and SharePoint Deployment Configurations.

Introduction

A Deployment Step defines the order in which custom commands are called and which commands are associated with the required CanExecute and Execute methods. As with SharePoint Commands, a Deployment Step may be referenced by numerous Deployment Configurations and are surfaced in the SharePoint configuration page of the project properties. They can be explicitly defined as part of an immutable configuration or mixed and matched within design-time configurations specified by the developer.

Continuing the previously established scenario, in which we created custom SharePoint Commands to remove orphaned List Instance objects from a site after updating the associated List Template, the next step in the process is to create a SharePoint Deployment Step which calls the custom commands. For all intents and purposes, a custom Deployment Command is simply a pointer which allows users to select a specific piece of functionality in the configuration settings and bundle one or more sets of functionality into a packaged Deployment Configuration. In our example, the new Deployment Step will call our DeploymentCommands.SPCommand.ListExists and DeploymentCommands.SPCommand.DeleteLists custom commands when the developer adds it to a configuration and deploys the solution within Visual Studio 2010.

Setting Up the Project

As mentioned previously, SharePoint Commands must be compiled using the .NET 3.5 Framework since they reference the core SharePoint 2010 assemblies; however, Deployment Steps and Deployment Configurations both require .NET Framework 4.0. In order to account for the different platform requirements, we must add a new project to the solution which will contain classes for both steps and the configuration. The final VSIX package, which will be created in a third project, will bundle both sets of assemblies together for activation within Visual Studio.

Begin by opening the Contoso.CustomDeployment solution and adding a class project with a namespace of Contoso.DeploymentSteps (the project should default to the .NET 4.0 Framework):

Writing the Code

The Deployment Step performs two functions: 1) Calling the DeploymentCommands.SPCommand.ListExists method to determine if any lists of the specified type in the target site exist, and 2) If any do exist, executing the code contained in the DeploymentCommands.SPCommand.DeleteLists method to remove them before re-deploying the solution. Deployment steps must include an ExportAttribute of Type IDeploymentStep and reference the Microsoft.VisualStudio.SharePoint.Deployment and System.ComponentModel.Composition namespaces. Furthermore, each Deployment Step has a collection of IDeploymentStepInfo parameters which describe the step, specify its display name and provide a message to be displayed in the Visual Studio IDE status bar while executing.

Attributes and Naming Conventions

As with SharePoint Commands, Deployment Steps are referenced by their literal string name which is defined as part of an attribute decoration on each class. There are no explicit rules pertaining to naming conventions; however, as the use of custom Deployment Steps grows within a development team it may be necessary to enforce some kind of explicit notation. For this example we will use a dotted hierarchy which includes the namespace but this is simply an arbitrary choice and has no bearing on the overall functionality.

Methods

Begin by creating the RemoveListInstances class and include the necessary attributes. Bear in mind that the name applied in the DeploymentStep attribute will be used later in the Deployment Configuration to reference the step:

using System;
using Microsoft.VisualStudio.SharePoint;
using Microsoft.VisualStudio.SharePoint.Deployment;
using System.ComponentModel.Composition;

namespace Contoso.DeploymentSteps
{
   [Export(typeof(IDeploymentStep))]
   [DeploymentStep("Contoso.DeploymentSteps.RemoveListInstances")]
   class RemoveListInstances : IDeploymentStep
   {

   }
}

Before moving on to the actual methods, it will be necessary to define a variable for the Feature ID of the List Template Feature created in the Contoso.CustomLists project (refer to the code samples in Part Two of this series). The GUID for the Feature can be located by opening the Contoso.CustomLists.Orders.Feature and clicking on the "Manifest" option in the Feature Explorer – this exposes the underlying XML from which the ID may be copied. In addition, we will also define the IDeploymentStepInfo parameters:



   class RemoveListInstances : IDeploymentStep
   {
   private string definitionFeatureId = "2190859b-344a-4e97-8ba9-f59537e202f6";

      public void Initialize(IDeploymentStepInfo stepInfo)
      {
         stepInfo.Name = "Remove List Instances";
         stepInfo.StatusBarMessage = "Deleting lists...";
         stepInfo.Description = "Removes all list instances associated with the specified list template.";
      }
   }

 

The first method to be defined invokes the DeploymentCommands.SPCommand.ListExists method within the custom Deployment Command class by its attributed name and passes in the value stored in the definitionFeatureId variable. Execution of the command is achieved by utilizing the ExecuteCommand of the IDeploymentContext and ISharePointProject.SharePointConnection interfaces:



      public bool CanExecute(IDeploymentContext context)
      {
         bool b = false;

         b = context.Project.SharePointConnection.ExecuteCommand<string, bool>("DeploymentCommands.SPCommand.ListExists", definitionFeatureId);

         if (!b)
         {
            string message = ("No lists of the specified type exist in target web.");
context.Logger.WriteLine(message, LogCategory.Warning);
         }

         return b;
      }

The above code returns a Boolean value indicating whether or not any List Instances associated to the specified Feature ID exist within the target site. If they do, the Execute method can be called; if not, a message is logged to the IDE as a Warning and the step terminates.

The final Execute method is quite simple: it logs a status message indicating that it is running and calls the DeploymentCommands.SPCommand.DeleteLists method of the Deployment Command class, passing in the definitionFeatureId value as a parameter:



      public void Execute(IDeploymentContext context)
      {
         context.Logger.WriteLine("Removing list instances...", LogCategory.Status);
         context.Project.SharePointConnection.ExecuteCommand("DeploymentCommands.SPCommand.DeleteLists", definitionFeatureId);
      }

Building and Packaging

As with the Deployment Command project, at this stage there is nothing more to be done other than to build the project and insure it compiles correctly. Later, in the VSIX portion, we will discuss how to include the resultant assemblies in the final deployment package.

Testing

While the custom command methods were easily testable, the same cannot be said for the Deployment Steps or Deployment Configuration. This is primarily due to the fact that the steps are designed to run as part of the Visual Studio host process and rely upon context information only available at runtime. It may be possible to mock or Mole the containing processes to derive state and context information but the code required to do so is well beyond the scope of this tutorial. Refer to the TypeMock forums and PEX/MOLES documentation for more information on this topic.

Conclusion

SharePoint Deployment Steps build upon SharePoint Commands by providing a method for referencing custom commands and a functional element which the developer can select as part of a custom deployment solution. They can be used individually or packaged together in a custom Deployment Configuration. In Part Four of this series we will discuss the creation of a custom configuration that utilizes the step defined in our example code. In Part Five, the final article in this series, we will investigate how the commands, steps and configurations are activated within Visual Studio 2010 and their effects on the deployment of our List Template solution.

 

SharePoint 2010 Code Deployment, Part One

SharePoint 2010 Code Deployment, Part Two

 

The End of a MacBook Era

A lot of people have noticed that I've ditched my MacBook Pro in favor of a Dell Latitude. I've posted a lot about my trials and tribulations with the MacBook here, here, here and here. I loved my MBP but there are a number of reasons why I had to ditch it in favor of a true Wintel machine:

  1. Drivers. The BootCamp drivers on the pre-Unibody MBP's were pretty darn good – I had no trouble running Vista or Server 2003/2008 and Apple was one of the first to have native x64 drivers for both. I assumed – wrongly – that the same would apply to the Unibody MBP's but that was never the case. The switchable graphics on these machines made running Vista/Windows 7/Server 2008 a complete nightmare. The nVidia card would lock into high performance mode and the thing would get so hot you could fry an egg on it. Naturally, this led to horrible battery life and with the aluminum casing spreading the heat around it was almost impossible to use after a few minutes. The trackpad never worked quite right and Bluetooth was a complete joke. Perhaps worst of all, when connected to a projector the video card would lock into 640x480 and there was no way to increase the resolution. And did I mention using the Express Card slot to connect to an eSATA drive? Yeah, that doesn't work, either. No matter how much people complained in the support forums Apple never stepped up to the plate to fix the drivers (and still hasn't). I realize that nVidia is very much to blame in this situation but I'm pretty sure that if Apple had put pressure on them they would have released a fix.
  2. Ports. At first I didn't miss having a few extra USB ports but after it while it became a real hassle. It wasn't only having two ports that caused me grief – they are also positioned too close together. Anytime I put in my 3G dongle or any one of a number of other peripherals they blocked the other port and it was effectively useless. Just about the only things that plug into the FireWire ports are portable hard drives, which would have been fine except that the drivers never seemed to work right under Vista or Server 2008. So for all intents and purposes I was left with one USB port. That just ain't gonna cut it. And what on earth is with Apple's decision to replace the ExpressCard slot with an SD slot? That just makes no sense – there are a ton of peripherals which use the ExpressCard form factor – including multi-card readers so I can read and SD if I really need to – but you can't do much with just and SD slot. I'm still shaking my head over this one.
  3. Expansion. When you use a lot of virtual machines like I do you're forced to have a second (or third or fourth) drive to put them all on. Sure, you can use the FireWire or USB ports but both are pretty slow and there are a lot of situations where presenting with a drive hanging off your machine is difficult (some podiums leave you no room at all for peripherals). I've seen people attach portable drives to the lid of their machines but a) I really didn't want to mar the finish by sticking a Velcro strip on it, and b) the hinge on the Unibody MBP's isn't as tight as it could be so the weight of the portable drive would drag it down to the fully open position which can be hard to view (especially with the high-gloss screen). What I really needed was an expansion bay like the Dell's and Lenovo's had but the design of the MBP's won't accommodate one. This may sound trivial but it turned out to be a real hassle.
  4. VMWare Fusion. All the issues with running Vista and Server 2008 forced me to use Mac OS X. I don't really have any complaints about the OS, although there were things that seemed a whole lot easier to do in Windows, but what really got on my nerves was VMWare Fusion, which is a pale shadow of VMWare Workstation for Windows. I'm not sure why VMWare can't seem to figure out how to release a full-blown virtualization client for Mac – lack of support for snapshots and clones is just ridiculous. Not to mention the fact that Workstation is much faster than Fusion running the same VM's. This isn't Apple's fault but it is a primary reason why the Mac platform doesn't cut it for the way I work.
  5. DisplayPort. Ugh. This is a complete PITA. Offering the latest and greatest display connections is all well and good so long as you leave the old tried-and-true VGA connector intact. Plenty of PC manufacturers have figured this out but Apple appears to be clueless. This isn't just a Windows problem – I was forever trying to find the stupid adapter to allow me to connect to a projector or monitor in Mac OS. Heaven forbid you lose it, like I did on more than one occasion, and have to hope against hope that there's another Mac junkie around who has one. And I'm not the only one – I still keep a Display Port to VGA adapter in my bag in case I come across some poor soul in the same situation.
  6. Docking. Over the years I have come to rely upon the ability to dock my notebook and have instant access to a full keyboard, multiple monitors, and the range of peripherals I keep scattered across my desk. Except for the 13" versions, the MBP is no small machine – finding a place for it to be open yet out of the way can be a real problem. Worse, you can't even close the lid and tuck it under a monitor stand as the heat vents are on either side of the keyboard facing upwards. Try it and you'll have a fried hunk of aluminum in nothing flat.

The bottom line is that MacBooks, regardless of whether or not they put "Pro" in the title, are not designed for business use. It's a PC world out there and Apple isn't doing much to bridge the divide. Perhaps I shouldn't have had such high hopes for the platform but it seems to me that the folks in Cupertino would have gotten the message by now. Based on how many people I saw at TechEd and SharePoint Conference toting MacBooks, it seems there is a pretty substantial market for Windows running natively on Apple hardware. There are probably a large number of people like myself who love the form factor but just can't use the machines for day-to-day work tasks. And that's a real shame.

So, until I find a really good use for it, I've got a very expensive paper weight sitting on my desk just begging to be used for the good of mankind. Who knows, maybe I'll dream up a cool iPhone app at some point…anyone got a 57x57 glassy cowboy hat logo sitting around that they're not using?

SharePoint 2010 Code Deployment, Part Two

Part One of this series gave a general overview of SharePoint 2010 code deployment using Visual Studio 2010. Now it's time to dig deeper and take an in-depth look at how developers can customize the deployment process. We will begin at the lowest level by creating some custom SharePoint Commands, then move into creating Deployment Steps which utilize those commands and a Deployment Configuration that combines the Steps into a single deployment option. Finally, we will package it all together and use the Visual Studio Extensions and Managed Extensibility Framework to deploy our customizations as a VSIX package.

Introduction

The basic unit of work for 2010 code deployment is the SharePoint Command. This is how developers interact with the SharePoint Object Model during the deployment process. Due to the fact that SharePoint Commands must run in a separate process to bridge the 32-bit/64-bit divide, they must be created inside of a separate project. How the project is designed, the number of classes in each project, and which methods to include in each class, are decisions left entirely up to the developer. As I mentioned previously, there are as of yet no best practices relating to the composition of custom deployment projects, but for ease of maintenance and reusability I would recommend that each class function as a relatively self-contained unit with the minimum number of methods required to achieve the desired functionality. As time progresses, it may be useful to have a base utility class which implements helper methods used by various other classes, but for the time being we will assume that all the necessary code will reside within a single class.

The scenario for this example is pretty straightforward. We will create a List Definition and an associated List Instance. Upon deployment, the SharePoint Command will check to see if there are any existing List Instances associated with the List Definition Feature and remove them if it finds any before deploying a new version of the List Definition. This will insure that there are no orphaned lists which inherit from the previous Template.

Setting Up the Project

In order to implement a custom Deployment Configuration for our scenario, we will need two separate Visual Studio solutions – one for the List Definition/List Instance and one for the custom deployment. I won't go into detail on the first solution as it can easily be implemented using the new SharePoint Project Items and following the prompts for creation of a List Definition. The following graphic illustrates the solution:

Once this is in place we can move on to creation of the deployment solution. This solution will require three separate projects – one for the VSIX package, one for the Deployment Step and Deployment Configuration, and one for the SharePoint Commands. They are separated logically by type of functionality as well as.NET Framework requirements – the VSIX package and Deployment Step/Configuration projects require .NET 4.0 while the SharePoint Command project requires .NET 3.5. We will begin with the SharePoint Command project as it is at the bottom of the stack from a referential perspective (the Deployment Step references the SharePoint Commands, the Deployment Configuration references the Deployment Step, and the VSIX project references them all).

Begin by creating an empty solution and adding a class project for the SharePoint Commands. Be sure to set the .NET Framework version to 3.5 for the SharePoint Commands project, which in this example is using the Contoso.DeploymentCommands namespace:

Writing the Code

There are two distinct pieces of functionality in this command. First, it will be necessary to determine if any lists deriving from the List Definition Feature exist. This will enable the subsequent Deployment Step code to determine if it should continue executing or terminate and log a message to the IDE. Second, if any lists do exist, they will have to be removed from the list collection of the target site. There is no need to pass any state information back to the Deployment Step in this scenario; however, other command types may require success or fail messages to be transmitted, which can be achieved by setting the method type to 'string' and returning an appropriate value, or by using an integer count, or by other various means.

It will be necessary to reference the Micrsoft.VisualStudio.SharePoint.Commands namespace (which is included with the Visual Studio Beta 2 SDK) along with the standard Microsoft.SharePoint namespace. This is the only project within the custom deployment solution in which we can directly access the SharePoint object model due to the fact that Visual Studio is a 32-bit application while SharePoint 2010 is limited to only 64-bit execution.

Attributes and Naming Conventions

All SharePoint Commands are referenced by their literal string name which is defined as part of an attribute decoration on each method. There are no explicit rules pertaining to naming conventions; however, as the use of custom commands grows within a development team it may be necessary to enforce some kind of explicit notation. For this example we will use a dotted hierarchy which includes the namespace but this is simply an arbitrary choice and has no bearing on the overall functionality.

Methods

Begin by creating the SPCommand class (again, no explicit naming conventions are required and it may be necessary to come up with a more structured naming convention over time).

using System;
using Microsoft.SharePoint;
using Microsoft.VisualStudio.SharePoint.Commands;

namespace Contoso.DeploymentCommands
{
  
public class SPCommand
  
{
  
}
}


Next, we will add the first method which determines if a List Instance deriving from the specified List Definition Feature exists. We will decorate the method with an attribute which specifies a name for future reference by the Deployment Step.

using System;
using Microsoft.SharePoint;
using Microsoft.VisualStudio.SharePoint.Commands;

namespace Contoso.DeploymentCommands
{
  
public class SPCommand
  
{
     
[SharePointCommand("DeploymentCommands.SPCommand.ListExists")]
     
public bool ListExists(ISharePointCommandContext context, string featureId)
     
{
        
Guid templateId = new Guid(featureId);
        
bool bList = false;
         using(SPWeb web = context.Web)
        
{
           
SPListCollection lists = web.Lists;
           
foreach (SPList list in lists) 
            
{
              
if (list.TemplateFeatureId.ToString() == templateId.ToString()) 
              
{
                 
bList = true; 
                  
break;
              

            
}
        
}
        
return bList; 
      
}
  
}
}


Note that the method is invoking the new ISharePointCommandContext interface. This interface provides contextual information for the command which is passed in from the Deployment Step. We are also capturing the ID of the List Definition Feature as the code will need this ID to identify any derived List Instances. The method itself simply iterates the SPListCollection object and identifies any SPList objects whose TemplateFeatureId property matches the GUID passed in from the Deployment Step. We only need one match to satisfy our requirements, so a Boolean value is set when a match is found and this value is returned to the Deployment Step. If no match is found it returns the default value of 'false'. Also take note of the fact that the SPWeb object is already available to us via the context, much like an Event Receiver or Feature Receiver.

Now that we have code to determine if a list associated with the specified Feature exists, we can add a method to perform the task of removing such lists from the list collection. As with the previous method, begin by decorating the method with an attribute which specifies the name that will be used in the Deployment Step, then add code to iterate the list collection, match the TemplateFeatureId value, then remove the list object and update the SPWeb object.

[SharePointCommand("DeploymentCommands.SPCommand.DeleteLists")]
public void DeleteLists(ISharePointCommandContext context, string featureId)
{
  
Guid templateId = new Guid(featureId);
  
using (SPWeb web = context.Web)
  
{
     
SPListCollection lists = web.Lists;
     
for (int i = lists.Count - 1; i >= 0; i--)
     
{
        
if (lists[i].TemplateFeatureId.ToString() == templateId.ToString())
        
{
           
lists[i].Delete();
           
web.Update();
        
}
     
}
  
}
}


We now have two commands, DeploymentCommands.SPCommand.ListExists and DeploymentCommands.SPCommand.DeleteLists, which encapsulate the functionality required by the Deployment Step. As previously mentioned, you may wish to add error handling logic in the DeleteLists method and return a string, integer or Boolean value which can then be used by the Deployment Step to determine whether or not the lists were actually deleted, or even log a message with the list names or ID's that were removed.

Building and Packaging

At this stage there is nothing more to be done that to build the project and insure it compiles correctly. Later, in the VSIX portion, we will discuss how to include the resultant assemblies in the final deployment package.

Miscellaneous Considerations

It is worth pointing out that the deployment process and execution of SharePoint Commands is not an area in which much can be done to enhance performance. Certainly, if the commands being executed are enumerating list items or accessing external data sources, then best practices should be employed in order to avoid lengthy wait times, but beyond that there are very few options for reducing the overhead incurred by the necessity of invoking and terminating a separate process to execute the command code, the processing done by SharePoint itself, recycling of application pools, and any extensions or add-ons to the Visual Studio IDE. In other words, don't expect the deployment process to be exceptionally fast but do take measures to insure that the command code being executed doesn't exacerbate the problem.

Testing

It should be fairly obvious that the SharePoint Command code is just as testable as any other code running against the SharePoint Object Model. From a Unit Test perspective, developers can approach SharePoint Commands as stand-alone classes which are developed and tested outside of the deployment process using whatever methods they prefer – TypeMock, NUnit, XUnit, PEX/MOLES, etc. By structuring the projects in the manner suggested, the command methods may be fully tested prior to adding the dependencies upon the deployment interfaces (SharePointCommand, ISharePointCommandContext), which may then be added after the test cases are satisfied. Obviously, this means that subsequent testing will have to account for the integration issues brought about by including the deployment interfaces. One possible solution to this problem would be to abstract each of the core methods into a separate set of utility classes which receive the context objects and parameters from the command. This would permit the use of mock objects or parameterized tests without requiring the deployment framework dependencies.

To illustrate this, consider separating the code into two separate classes and abstracting the core functionality:

SharePoint Commands

using System;
using Microsoft.SharePoint;
using Microsoft.VisualStudio.SharePoint.Commands;

namespace Contoso.DeploymentCommands
{
  
public class SPCommand
  
{
     
[SharePointCommand("DeploymentCommands.SPCommand.ListExists")]
     
public bool ListExists(ISharePointCommandContext context, string featureId)
     
{
        
bool bList = Contoso.DeploymentCommands.Utilities.VerifyListByTemplateId(context.web, featureId);
        
return bList;
     
}
     
[SharePointCommand("DeploymentCommands.SPCommand.DeleteLists")]
      public void DeleteLists(ISharePointCommandContext context, string featureId)
     
{
        
int i = Contoso.DeploymentCommands.Utilities.RemoveListByTemplateId(context.web, featureId);
        
if (i < 1)
           
throw new System.Exception();
     
}
  
}
}


Utility Class

using System;
using Microsoft.SharePoint;

namespace Contoso.DeploymentCommands
{
  
public class Utilities
  
{
     
public bool VerifyListByTemplateId(SPWeb web, string TemplateId)
     
{
        
Guid templateId = new Guid(TemplateId);
        
bool bList = false;
        
using(web)
        
{
           
SPListCollection lists = web.Lists;
           
foreach (SPList list in lists)
           
{
              
if (list.TemplateFeatureId.ToString() == templateId.ToString())
              
{
                 
bList = true;
                 
break; 
               
}
           
}
        
}
        
return bList;
     
}
     
public int RemoveListByTemplateId(SPWeb web, string TemplateId)
     
{
        
Guid templateId = new Guid(featureId);
        
int x = 0;
        
using (web)
        
{
           
SPListCollection lists = web.Lists;
           
for (int i = lists.Count - 1; i >= 0; i--)
           
{
              
if (lists[i].TemplateFeatureId.ToString() == templateId.ToString())
              
{
                 
lists[i].Delete();
                 
web.Update();
                 
x = x + 1;
              
}
           
}
        
}
        
return x;
     

   
}
}


Conclusion

SharePoint Commands provide a means for developers to interact with the SharePoint Object Model when creating custom deployment solutions. They run in a separate process in order to overcome the x86/x64 limitations of Visual Studio with SharePoint and are flexible enough to encapsulate any OM-related functionality. They also serve as the base building block for deployment customizations. In Part Three of this series we will explore the next link in the chain, Deployment Steps, how they relate to and reference SharePoint Commands, and how they are used within the Visual Studio IDE.

SharePoint 2010 Code Deployment, Part One

SharePoint 2010 Code Deployment, Part Three

 

Happy New Year 2010

Hard to believe that another year has come and gone. I've never been one for predictions and resolutions, which I'm no good at keeping anyway, but I think 2010 is going to be a big year in SharePoint land. For starters, SharePoint 2010 really will be a game-changer. I believe with this release that we will see SharePoint reach its potential in many organizations and adoption rates will be phenomenal. Developers finally have the tools they need to create killer applications and administrators have a much richer set of controls to manage their environments. Many of the almost-good-enough-but-not-quite features in 2007 (BDC, Records Management, Content Deployment, Excel Services, Search, and Shared Services, just to name a few) have been greatly improved and will generate a great deal of interest in using Enterprise features. Best of all, the reliance upon clunky web parts for content management and the slick new UI will make the end user experience a great deal better.

As AC mentioned, there are a few areas that will demand more focus from developers in 2010. Silverlight will be huge and I anticipate that we'll see some very engaging and visually appealing solutions on that front. Creating service applications will also be a big area of interest. Lots of people will be getting on the VSIX bandwagon and extending Visual Studio 2010, especially in relation to one of my favorite new areas, code deployment. I also expect to see some cool extensions to the new SharePoint Project Items and Project Extensions. We'll all become more proficient with WCF and, despite their drawbacks and limitations, sandboxed solutions should be a big part of all our lives. I'm not sure if people will jump with both feet into Windows 7 development with the Client OM seeing as how there are so many new areas of server-level development but it's certainly an area to watch. I anticipate that the trend of vendors rushing into the space will continue and I'm looking forward to seeing some cool new solutions to fill gaps where the base product leaves off.

As usual, I'll be bouncing around the globe doing various events and conferences. There will be a lot of community action taking place, with expanded user group meetings in the UK and lots more SharePoint Saturdays and TechCons, not to mention the big get togethers like TechEd and SharePoint Conference. I'll be working hard with my ISPA compatriots to expand our value to the community and increase the number of user groups around the world (look for some big announcements on that front early on in the new year).

So here's to an exciting 2010. May it prove fruitful and fun. Happy SharePointing!

 

1 - 10 Next
Eric Shupps