So I'm really getting into good habits using Features, whereby every little piece of SharePoint code I write or page I customize must ultimately be deployable. All custom SharePoint functionality should be treated no differently than any other piece of software: it should be deterministic, uninstallable, and scalable. And pretty.
And whenever you have "programmatic" and "customize" and "SharePoint" all in the same sentence, expect that sentence to end with "SmartPart." I've said it time and time again, but this little ditty has really streamlined SharePoint development. Check it out here.
It's also really easy to configure: just deploy your UserControl to a specific location on your server, drag a SmartPart into a WebPart page, and select that UserControl in the SmartPart properties. I know that's very high level; follow the above link for all the details if you're unfamiliar with the SmartPart.
However, when it comes to programmatically provisioning SharePoint sites and pages, I wasn't able to Google my way to a method of creating a SmartPart in code and adding it a page. And I was really surprised! I mean, for such a popular tool in the SharePoint community to have no mention anywhere of automated provisioning...I'm starting to wonder if people are dragging-and-dropping loose files onto their production SharePoint server (or...yikes...servers) and calling it a deployment...
Well, I'd much rather hang out on a production server as little as possible. I want to remote in, double click a installer, then get out. And the way to accomplish that with SharePoint is through Features and Solutions. And the way to use custom code to get this done is to create a Feature Receiver. Read more about programmatic entry points to Features here.
Here's some sample code of a Feature that programmatically adds a SmartPart to a page:
This code is in the context of the FeatureActivated override of a class that inherits from SPFeatureReceiver. First, we create an instance of the SmartPart class. Just grab the DLL from the downloaded installation files, and
reference it in your project. Then, to wire it up to a user control, set the "USerControl" property as shown. It wants a relative path to the .ascx file.
Finally, using the SPLimitedWebPartManager class, we can programmatically add or remove web parts from a web part page. Just pass what will be the URL of the page in question to an SPWeb object's "GetLimitedWebPartManager" method, and you've got your manager. Using this, you can do anything that can be accomplished via the "Edit Mode" UI of a web part page. It's awesome.
If this is the SPLimitedSPLimitedWebPartManager, I wonder what the SPFullBlownFullyLoadedDeluxeEditionWebPartManager can do!
Finally, I wanted to go over the assumptions of this code in a bit of detail. First of all, if we're creating SmartParts programmatically or even just using them in our portal, then the SmartPart feature needs to be installed and activated. (Again, everything you need to know is on the link above.)
I think it's a safe assumption to make, but to be explicit and ensure that one double-click of your installer will always work on any server, you can do things like "slipstream" the SmartPart solution into your own so they install at the same time, or take an Activation Dependency on the SmartPart. What the later means is that your feature will not install unless the SmartPart is currently activated. Here's the XML to nestle as a child node under the node in Feature.xml:
The rest of the assumptions are basically that the Solution which installs this Feature also copies all the necessary source files of your user control to the correct places. And don't slack on this! The really hard part of SharePoint deployment is figuring out how to declaratively or procedurally provision functionality. The easy part (although not as thrilling) is all the "supporting" tasks we need to perform, such as file copies, gacutils, and iisresets. But we gotta do it; achieving trivial deployments is really what makes our work elegant.