Posts filed under ‘Programming’

Sharepoint Solutions file (WSP) Schema

Sharepoint features, webparts, and files are deployed using a solutions file with the extension wsp. The wsp files are actually just a “.cab” file, which is the native Windows archive format. The content of the solutions file must follow a particular schema. Unfortunately, the schema and relationships are not very well documented.  The following is an attempt to clear up the confusion.

The Hive

Let’s start backwards from the deployment and look at the hive. The hive is where SharePoint files are installed. When we deploy a solution package using the stsadm.exe command:

stsadm -o addsolution -filename MyFeature.wsp

The stsadm command copies the files from the WSP to the hive. By default, the hive is located in C:\Program Files\Common Files\Microsoft Shared\web server extensions\12 on the WSS server.

Typically, when you create a new WSS project, you want to replicate the directory structure of the hive in your project. The reason will become apparent later when we create the solution. In addition, if you plan to use a tool like wspbuilder, the tool expects you to organize the directory in the same manner as the hive.

The Solutions File

Next, we look at the solution, which has an extension of “.wsp”. The solutions file contains everything needed to deploy your software. The solutions file is just a cab file, so we can open it by changing the extension from “.wsp” to “.cab” and then double-click on it.

Here’s an example of the content of a WSP file:

Manifest.xml
MyFeature\Feature.xml
ControlTemplates\MyFeatureForm.ascx
MyFeature.dll

Notice the Manifest.xml file at the beginning. A solution file may  hold a variety of different files, but it always has a manifest.xml file. This manifest file list what is in the solutions file. Let’s examine the manifest.xml next.

Manifest.xml file and how it relates to the WSP file

The manifest.xml file specifies how the WSP file is put together. Here’s what the manifest.xml file for the above solutions file looks like:

<Solution SolutionId="4AFC9950-F354-4439-B941-51377E854F2B" xmlns="http://schemas.microsoft.com/sharepoint/">
  <FeatureManifests>
    <FeatureManifest Location="MyFeature\Feature.xml"/>
  </FeatureManifests>
  <TemplateFiles>
    <TemplateFile Location="ControlTemplates\MyFeatureForm.ascx"/>
  </TemplateFiles>
  <Assemblies>
    <Assembly  DeploymentTarget="GlobalAssemblyCache" Location="MyFeature.dll"/>
  </Assemblies>
</Solution>

This manifest tells us that this WSP has an Assembly (the dll), a user control (ascx), and a feature.xml file. There may be additonal files in the WSP. You can even embed a movie into the WSP. But unless the file is specified in the manifest, the installer will skip over it during installation.

The root element of the manifest is always <Solution>. The solution ID is a GUID that uniquely identifies your solution (the deployment package) to SharePoint. When you create a new package, you must always create a new GUID. The other elements specify what is in the WSP file and where to find them via the location attribute. The location is the most confusing part. When I first programmed SharePoint, I thought the location must either closely follow the 12 hive’s file structure or the location must be totally independent of the 12 hive. It turns out that both assumptions are false. The location does actually follow the 12 hives, but the root location will change according to the element type.

Let’s examine the element <FeatureManifest>, the location is based on root of the FEATURES at 12\TEMPLATE\FEATURES. If we deploy this WSP, the location tells it to look for the feature.xml file in MyFeature directory in the WSP file and deploy it to 12\TEMPLATE\FEATURES\MyFeature\feature.xml.

If we take a look at the element <TemplateFile> for the control “MyFeatureForm.ascx”, the location is based on the root of the TEMPLATE, which is at 12\TEMPLATE. If you examine 12\TEMPLATE in the hive, you’ll notice that there is already a CONTROLTEMPLATES and there is already a list of controls there. When we deploy, the manifest will tell the installer that the file MyFeatureForm.ascx  is located in ControlTemplates directory in the WSP and that the MyFeatureForm.ascx should be deployed to 12\TEMPLATE\CONTROLTEMPLATES\MyFeatureForm.ascx.

Finally, the <Assembly> element specifies where the DLL is located. The root for this element is the web application bin file if you specify DeploymentTarget=”WebApplication”, and the GAC if you specify DeploymentTarget=”GlobalAssemblyCache”. Hopefully by now, you can guess how this works. In the above example, the <Assembly> element tells the installer to look in the root of the WSP file for the MyFeature.dll and deploy it to the GAC, which is typically located in C:\Windows\System32\Assembly on most systems.

The following is a small table listing the element and where the root of the location in the hive.

Manifest Element Location’s Root
ApplicationResourceFile 12\Resources
Assembly Web Application bin or GAC
FeatureManifest 12\TEMPLATE\FEATURES
ResourceFile 12\TEMPLATE\FEATURES
RootFile 12
SiteDefinitionManifest 12\TEMPLATE\SiteTemplates
TemplateFile 12\TEMPLATE
WebTempFile 12\TEMPLATE

If you understand the concept that each manifest element has a different root, you will be able to use this knowledge to deploy your web asset to any where you want within the hive. For example, suppose you want to group your user controls (ascx) under a folder. So instead of deploying your user control files to 12\TEMPLATE\CONTROLTEMPLATES, you want it to deploy to 12\TEMPLATE\CONTROLTEMPLATES\MyProject. You can change the location from

    <TemplateFile Location="ControlTemplates\MyFeatureForm.ascx"/>

to

    <TemplateFile Location="ControlTemplates\MyProject\MyFeatureForm.ascx"/>

Keep in mind that not all combination makes sense or is valid. Features are always limited to one layer deep. If you try to specify location=”MyProject\MyFeature\feature.xml” for a FeatureManifest element, you will get an error message that you cannot go beyond one level deep. In additon, specifying location=”Myproject\MyFeature.dll” doesn’t make sense either because you’ll end up with a subdirectory inside the GAC.

Generating the WSP using a DDF file

While the manifest determines what’s in the WSP file, you still have to create the WSP file itself. Technically, you can manually build the WSP file by hand, but you can use a diamond definition file to build it for you during a compile. A DDF is basically an instruction file for building WSP files. Let’s examine the DDF file used to build the WSP example. This DDF file is placed in the root of the project folder.

.OPTION EXPLICIT
; Specify the output filename
.Set CabinetNameTemplate="MyFeature.wsp"
; Specify where to create the WSP file
.Set DiskDirectoryTemplate="..\Deployment"
; Compress the solution package
.Set CompressionType=MSZIP
; You always have a manifest file
manifest.xml
; Assembly gets placed in the top level
bin\Release\MyFeature.dll
; Features placed in location specify in FeatureManifest
.Set DestinationDir="MyFeature"
12\TEMPLATE\FEATURES\MyFeature\feature.xml
; User control placed in location specified in TemplateFile
.SET DestinationDir="ControlTemplates"
12\TEMPLATE\ControlTemplates\MyFeatureForm.ascx

The first important line is “CabinetNameTemplate”, which specifies what the outfile file name is going to be. The entry “DiskDirectoryTemplate” may look a bit odd, but it tells the builder where to put the output file. In this case, we say “..\Deployment”. The path is relative to the project’s home directory, so this will generate a Deployment directory into the your Visual Studio’s solution file’s directory and put the WSP file there. The idea is when you compile, all of the WSP file for all projects in the solution will end up in the same deployment directory.

The rest of the DDF handles the adding of files to the WSP archive. You specify the file using a path relative to your project’s root. In the above example, the first file written is manifest.xml and it expects the file to be in the root of the project.

For the assembly, you recall the location for the Assembly in the manifest was location=”MyFeature.dll”. The manifest expects this file to be in the root of the WSP. In your Visual Studio, the path is bin\Release\MyFeature.dll, so the builder will grab the file from your bin directory and add it to the WSP’s root.

The  next command is new to us, it said “.SET DestinationDir”. This is because the next item written is feature and the manifest expects it at “MyFeature\Feature.xml”. What we are doing is setting the write directory to “MyFeature” by setting the DestinationDir. Now all files will be written to the MyFeature directory, including the “12\TEMPLATE\FEATURES\MyFeature\feature.xml”.

Finally, we write the user control file. The TemplateFile location in our manifest specifies that it will be located at “ControlTemplates\MyFeatureForm.ascx”. We will use DestinationDir to set it to “ControlTemplates” and then write the user control, which is located in our project at “12\TEMPLATE\ControlTemplates\MyFeatureForm.ascx”.

The DDF file only define how the WSP is build. A utility call makecab does the actualy work. It reads the DDF file, copies the files in the DDF into the wsp. One way to have the files generated automatically is to add a script to the post compile event of your project.

cd "$(ProjectDir)"
MakeCab /f Package.ddf

Now when you compile your project, the event script will run and generate the WSP file.

Conclusion

With tools like WSPBuilder, you can now generate WSP file without fooling around DDF and Manifest files. However, it is still good to understand how the underlying mechanism works. I hope that you have found this article helpful.

March 6, 2009 at 10:20 am 14 comments

File not found error when you select New Webpart after installing SmartPart 1.3

Recently, I was asked to install SmartPart 1.3 on WSS 3.0. After installation, we encountered the following error when we attempt to create a new web part in the web part gallery:

File Not Found. at System.Signature._GetSignature(SignatureStruct& signature, Void* pCorSig, Int32 cCorSig, IntPtr fieldHandle, IntPtr methodHandle, IntPtr declaringTypeHandle)
at System.Signature.GetSignature(SignatureStruct& signature, Void* pCorSig, Int32 cCorSig, RuntimeFieldHandle fieldHandle, RuntimeMethodHandle methodHandle, RuntimeTypeHandle declaringTypeHandle)
at System.Signature..ctor(RuntimeMethodHandle methodHandle, RuntimeTypeHandle declaringTypeHandle)
at System.Reflection.RuntimeMethodInfo.get_Signature()
at System.Reflection.RuntimeMethodInfo.GetParameters()
at Microsoft.SharePoint.WebPartPages.SPWebPartSerializer.GetPersonalizableProperties()
at Microsoft.SharePoint.WebPartPages.SPWebPartManager.GetEffectiveWebPartType(Type webPartType, SerializationTarget serializationTarget, Boolean ignoreSupportsAttributeMarkup)
at Microsoft.SharePoint.WebPartPages.SPWebPartManager.GetEffectiveWebPartType(Type aspWebPartType, SerializationTarget serializationTarget)
at Microsoft.SharePoint.ApplicationPages.NewDwp.Page_PreRender(Object sender, EventArgs e)
at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e)
at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e)
at System.Web.UI.Control.OnPreRender(EventArgs e)
at Microsoft.SharePoint.WebControls.UnsecuredLayoutsPageBase.OnPreRender(EventArgs e)
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

Various sites indicated that Smartpart 1.3 requires AJAX extension 1.0. Because AJAX extension 1.0 is included in .Net Framework 3.5 SP1, I install that instead. However, this did not solve the problem. I found the solution in the comments on this post:

http://www.codeplex.com/smartpart/WorkItem/View.aspx?WorkItemId=2708

Apparently, SmartPart is binding to the older version of the System.Web.Extensions.  If I had installed an earlier version of the framework and the separate AJAX extension 1.0, it may have worked. The article does suggest a workaround.

  1. Go the the web.config of your WSS.
  2. Locate the section <runtime>, and within that <assemblyBinding>. There should be a list of <dependentAssembly> entries.
  3. Add the following entry:
<dependentAssembly>
<assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="1.0.61025.0" newVersion="3.5.0.0" />
</dependentAssembly>

What the entry does is redirect binding to the old version of System.Web.Extensions to the new version. The 3.5.0.0 version should have been installed to the GAC when you install Framework 3.5 SP1.

After this change, you will be able to create a new web part in the web part gallery again.

March 4, 2009 at 1:56 pm 7 comments


Calendar

June 2017
M T W T F S S
« Jun    
 1234
567891011
12131415161718
19202122232425
2627282930  

Posts by Month

Posts by Category