Let me just warn you up front, this is not going to be a very exciting post. Packaging is pretty boring. Nor is there anything original about it. I’m using a technique I first read about in articles by Ted Pattison back in about 2007. If I could still find those articles, this would be a very short post pointing you to them, but I did some rooting around looking for them and didn’t have a lot of luck, thus this post.
So first, there are a lot of ways to do this. You could use something like WSP builder, which reduces the tedium of doing SharePoint solutions quite a bit. You may even be able to use the SharePoint project templates built into Visual Studio 2013 (or available as extensions for 2012, but I haven’t found a way to get them not to include/deploy the assembly; I may just not have looked long enough). I’m sure there are other ways. If you already know one of them that you like, read no further. But in the end I decided that I wanted no external dependencies. I use Visual Studio 2013 Ultimate, and the SPEasyForms solution is a VS2013 solution, but the build is actually just a batch file calling makecab.exe so Visual Studio is not actually required.
I’m going to start from the bottom up with the element files. If you’ve been doing any kind of SharePoint development for a while, I hope these look somewhat familiar. The Visual Studio tooling for SharePoint has come a long way, but you still can’t do much without occasionally manually mucking around with element files. However, this tooling has come to hide many of the details of packaging solutions from you, which is why I felt this post was necessary. The first element file is SPEasyForms.AddOns.Assets.xml, which looks like:
<?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Module Name="SPEasyFormsAddOnsAssets" Url="Style Library/SPEasyFormsAssets/AddOns/2014.00.01"> <File Path="DefaultToCurrentUserAdapter.js" Url="DefaultToCurrentUserAdapter.js" Type="GhostableInLibrary" IgnoreIfAlreadyExists="True" /> </Module> </Elements>
The other element manifest is SPEasyForms.AddOns.ScriptLinks.xml, which looks like this:
<?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <CustomAction Location="ScriptLink" ScriptSrc="~sitecollection/Style Library/SPEasyFormsAssets/AddOns/2014.00.01/DefaultToCurrentUserAdapter.js" Sequence="57401" /> </Elements>
<?xml version="1.0" encoding="utf-8"?> <Feature Id="83d6bab2-b101-4816-bdbb-6ba82f3b03b0" Title="SharePoint Easy Forms Add-Ons" Description="Default to current user adapter." Version="126.96.36.199" Hidden="FALSE" Scope="Site" xmlns="http://schemas.microsoft.com/sharepoint/"> <ElementManifests> <ElementManifest Location="SPEasyForms.AddOns.Assets.xml" /> <ElementManifest Location="SPEasyForms.AddOns.ScriptLinks.xml" /> <ElementFile Location="DefaultToCurrentUserAdapter.js" /> </ElementManifests> </Feature>
The other thing to note is that this feature is scoped to site, which makes it a site collection feature. I generally make all features in sandboxed solutions site scoped, because the way sandboxed solutions are upgraded makes web scoped features a bit of a nightmare.
The last XML file is the Manifest.xml, which just assigns a unique id (GUID) to the solution and tells SharePoint where our one and only feature resides:
<?xml version="1.0" encoding="utf-8"?> <Solution xmlns="http://schemas.microsoft.com/sharepoint/" SolutionId="eec95124-c174-4cf2-9978-25a37d3375a8" > <FeatureManifests> <FeatureManifest Location="SPEasyForms.AddOns\Feature.xml"/> </FeatureManifests> </Solution>
.OPTION Explicit .Set DiskDirectory1="." .Set CabinetNameTemplate="SPEasyForms.AddOns.wsp" Manifest.xml .Set DestinationDir="SPEasyForms.AddOns" ..\Features\Feature.xml ..\Elements\SPEasyForms.AddOns.ScriptLinks.xml ..\Elements\SPEasyForms.AddOns.Assets.xml ..\Elements\DefaultToCurrentUserAdapter.js
@echo off makecab /f Package.ddf pause
cd ..\..\Package Build.bat $(ConfigurationName)