Part 1 - Part 2 - Part 3 - Part 4 - Part 5 - Part 6 - Part 7 - Part 8
"Previously on 'Prison Break'...I mean 'Solution Packages for Developers'"
My blog got quite a few extra visitors over the last couple of days since writing about SharePoint Development and "doing things the right way". A few people have been giving me "gentle" and "subtle" hints to start a series and based on the success of Paul Culmsee's various part articles I've decided to give him a run for his money...but in a different space to his primarily focused on Developer land.
"Telling a real 'SharePoint Developer' from a 'SharePoint User'"
So as I was saying in my previous post...there is this notion of SharePoint Solution Packages with Features. These Solutions can be deployed to the SharePoint Farm no matter how big or small. The beauty of this is that it allows you to write these packages in Visual Studio in XML and .NET code which can be put into source controll and gives a paradigm of a snapshot of a "Solution" that is deployed in an environment.
The dangers of SharePoint are very apparent, any business user can create whatever they like if they are given Owner rights and before they know it, have thrown Excel in the bin to run their business in, and have lots of SharePoint Lists (SPList) and plenty of SharePoint Designer (SPD) workflows running. Imagine after four months, the User comes to you and says "I'd quite like it if it could do this". So any half respectable Developer would backup the SharePoint Site (Web) or SiteCollection (Site) that it has been set up in and then restore it in their development environment. The Developer makes his changes in the SharePoint interface and shows it to the User and they love it and want it in Production that afternoon...after all they were so close and it didn't take more than half a day to do their bit.
The Developer can't backup and restore into Production because Production has been in use since they last did their backup and it would mean losing data. Did the Developer write down every last interface step he did to get to the point he's at now? Does he really want to do that all over again in UAT environment for handover? Does he then really want to do that all over again in Production? How long are these steps going to take? Is there a risk of forgetting something or configuring it incorrectly? Is this going to mean more than 10 minutes down time in Production and therefore out of hours work...you bet your last Rolo it does!
"No it won't take the same amount of time to create it in a Solution!"
So SharePoint gave us Solutions to allow us to guarantee that whatever is installed in one environment is the same as the next. Wouldn't it be nice if you could just point at the Development environment and click "create me a solution for all of this". "Yes, Jeremy, it'd be really nice". OK...now we're past the unrealistic expectations of Microsoft lets get with reality.
There is a platform here to do these things and there is considerable SDK documentation on the APIs....there isn't considerable documentation and samples for using the APIs. If you do a search for "SPLimitedWebPartManager" in Google/Live and see how many results come back that aren't SDK API pages (diigo) you'll notice hardly any results. This Manager is one of the core ways of adding/removing/modifying Web Parts on a page. For me this is one of the most obvious, key parts of any Solution Deployment you would try and write to automate your work. The samples go as far as deploying the Web Part to the Web Part Gallery, but do not show you how to easily add them to the page or modified existing ones or delete ones you don't require.
"Next Week on 'Battlestar Gallactica', I mean 'Solution Packages for Developers'"
In the next few weeks (before I jet set away for 3 weeks - don't worry I'll be back with more) I'll be posting some key scenarios that are done every day in the SharePoint User Interface, but replicated as deployable Solutions. I'll be using the tools mentioned in the last post and pointing to various resources for further information.
In the beginning...
To get your taste buds rolling, I thought I'd get started with one...and no I'm not doing "Hello World!". I'm going to show you how to deploy a SharePoint List (ListTemplate and ListInstance) completely in a Solution and I'll even throw in a Content By Query Web Part to display some data. Content By Query Web Parts are awesome, period (diigo). They can do so much...as Andrew Coates was saying at the last SharePoint User Group in Perth..."Leverage the Platform". Why write a web part in custom code to render a SharePoint List with a filter when you can use what's there OOTB. Yes I know it has it's limitations and I know Sezai will be throwing things at me next time he sees me. But seriously...lets not make things complicated "cos I can"..."Keep It Simple Stupid!" (KISS). They are a great way to leverage information by using Content Types and are proven to perform - Waldek Mastykarz clearly has more time on his hands than me to get this amount of evidence on it! I also have to give heaps of credit to "Mr STSADM" (Gary Lapointe) for giving plenty of sample SharePoint API codes which kick started in the right direction as there was hardly anything out there on this!
"Chapter One – Business User Land"
The Business User creates a List in a Site to store information on TV Shows with their "Season Number", "Episode Number" and "Air Date". The homepage of the Site will display the List in a web part along with other web parts not related to this project.
Now in the SharePoint User Interface the User would go to Site Actions, click on Create, select Custom List, create their list, create the columns, adding the List View Web Part, etc. Maybe ringing the Development team for support at various stages and expect instant help. I've uploaded a recording of this in action.
Business Users (5 minutes)
- Create List with custom Columns
- Create List View Web Part
"Chapter Two – Designer Land"
The Business User has gone to the IS department and isn't happy with how it is being rendered and wants to move away from a list like display to have headings and information render in a specific way.
So now the Designer goes away and takes a look at the List and creates a Content By Query Web Part and uses XSLT to render it how the Business User has asked. I've uploaded a recording of this in action also.
Designer (15 minutes)
- Creating xsl:template elements for stying Content By Query Web Part and formatting the custom columns
- Modifies the Content By Query Web Part .wepart XML to expose the custom columns and re-imports it
"Chapter Three – Developer Land"
So now the Business are really happy with this, but so far this has all happened in Production system and hasn't allowed Designers the ability to test that the rendering is going to work or that if they needed to add new columns etc it hasn't affected the Businesses day to day running. Chapter Three, allows you to get to this scenario.
In Developer land I would advise doing the same thing in some circumstances as the first two Chapters, even when you are a dab hand at coding straight away, but there are some design decisions to make at this stage.
- Site Content Types (and Site Field Types) vs. List Instance Columns
Columns will mean you cannot chose the List columns in the Content By Query Web Part when sourcing, grouping and filtering also may be re-use in Field Types in later developments.
- List Templates (with a List Instance) vs List Instance
List Instance will mean losing the ability to customise the Forms used with the List (in following posts I'll explain this further) – you'd simply have a ListInstance with Rows defined and no hook up to Content Types or custom forms and inherently workflow or records policies also.
- Content By Query Web Part vs. List View Web Part
List View Web Part won't allow for complete custom rendering to look non-SharePoint like...also can create custom CAML queries to filter and sort data in a more powerful way and also source data from multiple Lists over multiple sites over multiple Content Types.
- SPLimitedWebPartManager vs. AllWebParts
The advantage of using the API in the FeatureActivated event rather than using the Module Element of the Elements Manifest. I find there is more control and also, exporting the .webpart XML hard codes the List Guids which can be dynamically entered using the API.
NOTE: I'll be putting up a webcast of this chapter tomorrow evening with full source code listings.
So, the Solution requires the developer to create a Site (SPWeb) using the "Publishing Site" Site Template called "TV Show Schedule". The Site will have a SharePoint List Instance (SPList) with the ability to add a List Item (SPListItem) of a "Schedule" Content Type with "Season Number" (Int), "Episode Number" (Int) and "Air Date" (DateTime) extra column metadata (SPField) based on a created List Template (ListTemplate). The front default.aspx page (SPFile) will have a Content By Query Web Part that will display these items Grouped By "Title" and Sorted by "Air Date".
Designer (15 minutes)
- Creating xsl:template elements for stying Content By Query Web Part and formatting the custom columns
Developer (2 hours)
- Create a ListTemplate set of creation scripts
- Create a Content Type set of creation scripts
- Create a Field Type set of creation scripts
- Create a Content By Query Web Part to render on default.aspx
- Create a Solution package to deploy the Solution Feature to the Site Collection
- Create a install script to deploy the Solution to the Farm, create the new site and activate the Feature
Content Types (ContentType)
I would agree with doing it in the UI first for Content Types too, purely for the Content Type ID which intelligently stores its parent information within it and is just easier to create a new one in the interface and copy it yourself. I use CT Feature Creator as it creates XML quite easily very similar to Solution Generator for both Site Content Types and Site Columns.
SharePoint Lists (SPList, ListTemplate, ListInstance)
First things first we need to imitate what the Business User did in Chapter One in a programmatic way. As an example of this...run up Solution Generator which is part of the VSeWSS install and point it at the Schedule List that is OOTB when activating the publishing feature. You'll get a heap of files...the relevant ones are the ones in the folder named the same the List itself and will contain a schema.xml file along with other .aspx files such as Upload.aspx etc. Anyone who can put their hand up and can script a ListTemplate schema.xml with Views, Fields, Content Types, Security and Forms from scratch without any references needs help! Debugging these things when you have an error is hard and it doesn't give you line numbers of where you've screwed up...so with Lists, do them in the User Interface and generate them.
Stuff to change
- Solution Generator also doesn't give it a unique Type ID in the ListTemplate definition placed in the Manifest file – although it seems to work fine. It appears these have to be unique when attaching Event Receivers and appears to have to be unique and less than 1000 - this can be used if we want to include this list in a custom site definition.
- Solution Generator does add instances of ContentTypes in list rather than ContentTypeRef's..urgh! Same with Fields...urgh! So you need to manually change these.
- It will also create folders with spaces in it which will break STSDEV and the Solution package itself, so you'll have to rename your ListTemplate's accordingly. For some reason it doesn't have the same behaviour as SPField and give you x_20_x in replacement of a space...who needs consistency I say!
- Solution Generator doesn't work on Site Definitions other than WSS definitions.
- You'll also notice that if you script it with the UI interface content type then generate the Content Type from script that it won't match up as the <Fields> elements are instances on the list...the inheritance creates a copy. So it's best to create the Content Type first then install this as a Feature on the Site and then create a List and use Solution Generator to script it.
Content By Query Web Part (ContentByQueryWebPart)
Again, even with this one, it's easier to get a CBQWP going via the User Interface than it is to guess what the minimum properties of the API object is to get the damn thing running! Although when you start wanting to show non-OOTB columns you have to do some behind the scenes work (an MSDN article covers this) – again this is something I wouldn't expect a business user to be able to do. So the dangers here is that they use other Web Parts like ListViewWebPart without realising the power of the ContentByQueryWebPart.
Once that's all up and running and you want to script this you can spend the next half hour guessing what API Property Name maps to what Web Part Property in the User Interface!
"Chapter Four: You took how long to @!?%@ do this!?!?"
I'm sure we've all been there...Development Managers asking why it's taken us this long to do it when he can do it in the interface in 5 minutes (ie. Chapter One). So here's some ammo:
Time Saved in Deployment
Although there is a considerable amount of effort involved in writing the Solution compared to generating it all in the Interface...in the long run, on large team projects and multi-environment scenarios it wins hands down.
Guaranteed same end result
With it being scripted, it means that the same Solution will be created in each environment.
By forcing Developers to work in this way, it also ensures that everyone is working the same way. Microsoft is pushing this as a standard and as training courses start appearing for more than just "boot camps" these methods will mature.
Self-Documentation and reducing resource dependencies
It also ensures that everything is documented because if it isn't in the Solution package...it doesn't get installed into the next environment in the chain. So rather than relying on the Developer who developed it to deploy it to UAT, anyone can run the Solution package install.
By having the Solution in Source Control it ensures that if the initial Developer is sick for a week or his machine dies that all the work he's been doing is backed up and accessible to others.
Up to speed quickly
Fresh Developers on the scene can, from a fresh SharePoint Development environment, start pulling down the Solutions from source control and installing them and seeing how they fit together. Furthermore, once they're up to speed can work on the project.
By being able to recreate these Solutions in any SharePoint Farm means you can test them in isolation and also their dependencies. On top of this you can get environments up for debugging and stepping through code very quickly to separate solutions to find out what is causing the issues.
Script load and performance testing
For the more advanced projects, you can then also load test and performance test the solutions in UAT before pushing this into Production. For more on this go over to Paul Culmsee's "Why do SharePoint Projects Fail?" series.
"Chapter Five: Happy Ending"
The sooner you educate the Users that it isn't simply a case of "smashing it out" in Production the better:
- Messy/un-versioned master pages, page layouts, itemstyles.xml etc.
- No distinction in projects on site – grouping web parts, lists, styles, content types etc.
- High risk of deployments screwing up
- Better use for SharePoint Developers time!
- Undocumented Solutions appearing in Farms
"Chapter Six: Until next time"
So now we have a complete Solution which will deliver our scenario. In the next post I will go onto talk about getting a bit more complicated with the Content By Query Web Part and deploying some XSL and CSS as part of the package to "spruce" the Web Part.
Here are a few references to the core MSDN/Technet links that I've used...it's worthwhile checking out my Diigo links also.
SDK - http://msdn.microsoft.com/en-us/library/ms413687.aspx
SDK Schema - http://msdn.microsoft.com/en-us/library/ms442108.aspx
Technet - http://technet.microsoft.com/en-us/library/cc263289.aspx
SDK - http://msdn.microsoft.com/en-us/library/ms439657.aspx
SDK Schema - http://msdn.microsoft.com/en-us/library/ms475601.aspx
Technet - http://technet.microsoft.com/en-us/library/cc263360.aspx
Types - http://msdn.microsoft.com/en-us/library/ms474383.aspx
SDK Schema - http://msdn.microsoft.com/en-us/library/ms414322.aspx
SDK - http://msdn.microsoft.com/en-us/library/ms434313.aspx
Other good articles
- Andrew Connell and Rob Bogue are in the process of a series of web casts...more information here. Rob has also followed up from a Q&A after the web cast with even more valuable information!
- Chris O'Conner has just posted a similar series to what I am going to be doing here also.
- Heather Soloman also has some great articles on this area.
- Eric Shupps also has some kind advice on the subject.