September 2007 Entries

So I was asked how we could put a masterpage into a sharepoint site definition and have it set to be active when someone creates a site from the definition.  Before I got started on that, I asked about changes to the masterpage.  The response, was what I was expecting.  They wanted to have one central masterpage that all sites could use, and have it be selected by defualt.  So, this changes things a bit, instead of including it in the site definition, I suggested to drop it into a feature.  When creating a feature this way, you can use a feature reciever to set the current web's masterpage and (theme, etc.).  I have broken the steps up into parts for ease of use, and as it turns out, they also have a custom theme that they want setup.

The goals:

  1. Write a feature receiver and deploy it to a small farm.
  2. Write a masterpage into a feature that uses the feature receiver.
  3. Use the masterpage feature in the site definition.

Well I have posted a couple of times and listed this link.  (The link to the newly (August 22, 2007) release of the WSS 3.0 Extensions)

I wanted to take a minute to cover the biggest feature in my opition.

You can now manage WSP packages... without having an external tool to create a cab, and changing properties generated by VS that you would not consider Production.

I opened my blog web part solution that I have been cleaning up,

By clicking on View - > Other windows -> WSP View, you get the window

From here, you can expand the package and open the related files.  (I have already deployed this solution, so you can see that everything has been created already.) 

Now I want to push my package to a staging environment and then prod next week, so... I do not want GUIDs in my feature names (which will happen when using the normal VSeWSS 3.0)

Maybe you can see this (might be a bit small), but this is the project, and I have opened the specific feature and element files to change the names to remove the GUID from the end of the feature name.

After renaming the folders, and making sure the other files reflected the name change... I rebuild and deployed again.

Now on my local dev box, the BlogViewer_489.... is replaced with BlogViewer.

Now I can simply take my WSP file and drop it on Stage and Prod, and it is very clean.

Have fun!

Well I have visited this site about 5 times this week, and it is one of the most resourceful places to get a list of STSADM commands.

Here is the link.

Well apparently when working with variation sites, the sites will actually rename the lists, etc.  Luckily the fields are not renamed.  This could be an issue if you are not working with the English version (1033), that is alot to translate. 

I was asked to write a blog webpart that resided a site above where the blog was, we have a site definition that creates a site collection and several sites under it (Blog, Wiki, Team Site, Meeting workspace) and they wanted to hide the link to the blog site, and have blog items show on the homepage of the top level site in the site collection.  No big deal, I wrote a simple webpart getting the current site, then the subsite named "Blog" if it was there, then I noticed on the subsite called "Blog" there was a List called "Posts".  I customized a SPQuery to only include published items, and the last 5 items. 

SPQuery recentBlogPosts = new SPQuery();
//Changed type to number from ModStat, since in DE it is Genehmigt instead of Approved in EN.
recentBlogPosts.Query = "<Where><Eq><FieldRef Name=\"_ModerationStatus\" /><Value Type=\"number\">0</Value></Eq></Where><OrderBy><FieldRef Name=\"PublishedDate\" Ascending=\"False\" /></OrderBy>";

//set max results to 5
recentBlogPosts.RowLimit = 5;

The last line actually sets the limit per page, but I am only using the first page. (if you wanted to use more, see ListItemCollectionPosition).  I had used the type parameter in the SPQuery for ModStat = Approved, but in Germna this word also changed.  State 0 is approved.

After a couple of itterations I found that the items in the list still used the English version of the Fields on each SPListItem... thank god! 

So be cautious with webparts that work on variation sites.

-DK

Sorry for the delay, but I am back with the 3rd part in this series.

We want to get a site definition in place to use this new masterpage feature.  This is pretty simple in the long run.

I have created a site definition in VS 2005 from the blank site definition project that is included with the Extensions for WSS 3.0 CTP 1.1.

A blank site definition will create a couple of key files for you, default.aspx, onet.xml, siteprovisioning.cs, etc.

In the onet.xml file, we need to make a simple change to include the feateres we want, if they were set to "on" by default, then we will not have to do anything, the feature will be activated, and in turn fire the code we have in our feature reciever.  Pretty neat huh!

Snippet from my onet.xml:

<SiteFeatures>
<!-- BasicWebParts Feature -->
<Feature ID="00BFEA71-1C5E-4A24-B310-BA51C3EB7A57"/>

<!-- Three-state Workflow Feature -->
<Feature ID="FDE5D850-671E-4143-950A-87B473922DC7"/>

<!-- Master Page Feature with Reciever -->
<Feature ID="GUID of the Feature"/>

</SiteFeatures>

<WebFeatures>
<!-- TeamCollab Feature -->
<Feature ID="00BFEA71-4EA5-48D4-A4AD-7EA5C011ABE5"/>

<!-- MobilityRedirect -->
<Feature ID="F41CC668-37E5-4743-B4A8-74D1DB3FD8A4"/>

</WebFeatures>

Now you can see that depending on what you set for your feature (Site or Web) scope, depends on where you need to add a reference to it.

Save the template, and deploy the solution package to a site... then create a site of this type.  You will see that your masterpage has been set by the feature reciever. 

Well that wraps up the series for now, I will be back in a few weeks with an update on workflow or an eventhandler (not sure which yet).

-DK

And to write a masterpage inside a feature, well first we need a masterpage, you can just grab the default masterpage from your SharePoint site, or from the global folder, and then customize it a little for this example.  (it might be easiest to customize the masterpage in SharePoint designer from your site, not in the global folder, so you can see what things look like, then just copy the contents of the file to a new file)

There are two masterpages used in SP sites, a site master and a system master.  This feature has both included in the feature reciever, so make sure to include them here as well.  Basically the feature receiver will change the site properties, and this feature will make the included files visible (provisioned).  This feature uses a module (you can click here for more information about this) that references the files.

With that said, on to the feature:

There are WSS templates, and you can use the blank sharepoint template, but I would suggest to just create a blank project, and then just add files (after all we are only making a couple of files).

Create/add an XML file called Manifest.xml.  Create a solution Guid for it, mine looks like this:

<Solution SolutionId="GUID" xmlns="http://schemas.microsoft.com/sharepoint/">
  <FeatureManifests>
      <FeatureManifest Location="SetupLookFeel\feature.xml" />
  </FeatureManifests>
</Solution>

now, we need to add a feature, Create a folder matching the name of the feature (in our case) SetupLookFeel

Inside this folder we place the feature.xml file as well as masterpage files, and and element definition file.

Inside the folder, I first create the feature.xml file (create a new guid for the feature itself):

<Feature xmlns="http://schemas.microsoft.com/sharepoint/" Id="GUID"
Title="SetupLookFeel"
Scope="Site" - This could also be Web for a single site (site is used for site collection)
ReceiverAssembly="LookFeelFeatureReceiver, Version=1.0.0.0,Culture=neutral, PublicKeyToken=TOKEN"
ReceiverClass ="LookFeelFeatureReceiver.SetupLookFeel" >
<ElementManifests>
  <ElementManifest Location="Elements.xml"/>
</ElementManifests>
</Feature>

*TOKEN - Take note here, you will need to get the PublicKeyToken, when the assembly is in the GAC, you can get the properties of the file, and it will list the PublicKeyToken, or use SN -T assemblyname*(or .Net Reflector)

*GUID - You might also want to take note of the Feature GUID that was used here, we will be using it in the site definition

*If you set the Scope to Web, or Site, this determines where this feature shows up (if the hidden property is not set)

Now that we have the feature file in place, create an Element.xml file:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="NewMasterPages" Url="_catalogs/MasterPage" >
   <File Url="SystemMaster.master" Type="GhostableInLibrary" IgnoreIfAlreadyExists="True"/>
   <File Url="SiteMaster.master" Type="GhostableInLibrary" IgnoreIfAlreadyExists="True"/>
</Module>
</Elements>

Now drop the two masterpage files into the folder,  and we are ready to cab it up.  (There is a CTP to WSS extensions for VS 2005, 1.1 is out and has a new feature called WSP explorer.  Check it out here).  Rename your newly created cab file to MyFeature.wsp, and then deploy the masterpage.  (You can see my other posts, or stsadm.exe -o deploysolution -filename MyFeature.wsp)

No need to activate this yet, as we will include this in our next post.

1.  Write a feature receiver and deploy it to a farm:

Open visual studio and create a blank class project.

Add a reference to SharePoint.dll (it will be on your SharePoint server \program files\common files\Microsoft shared\web server extensions\12\isapi\)  I would suggest copying the dll's from there into one central location if you are not developing on a SharePoint server.

Open the class file and add the reference:

using Microsoft.SharePoint;

Now we are going to implement the feature receiver interface in our class:

public class SetupLookFeel : Microsoft.SharePoint.SPFeatureReceiver
{
public override void FeatureInstalled(SPFeatureReceiverProperties properties)
     {

     }

     public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
{

     }

     public override void FeatureActivated(SPFeatureReceiverProperties properties)
{

            //Get the current SPWeb object to make changes to the web properties
SPWeb currentWeb = properties.Feature.Parent as SPWeb;

            //Set the masterpage to our masterpages
currentWeb.MasterUrl = "_catalogs/masterpage/SystemMaster.master";
currentWeb.CustomMasterUrl = "_catalogs/masterpage/SiteMaster.master";

            //Other options can be set here as well, i.e.
//
            //currentWeb.ApplyTheme("ThemeName"); 
            //currentWeb.CustomizeCss("cssFileName");

            //Update the web with our changes
currentWeb.Update();

}

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{

            //Get the current SPWeb object to make changes to the web properties
SPWeb currentWeb = properties.Feature.Parent as SPWeb;

//Set the masterpage back to the default OOB masterpage
currentWeb.MasterUrl = "_catalogs/masterpage/default.master";
currentWeb.CustomMasterUrl = "_catalogs/masterpage/default.master";

            //Just make sure to undo other options that were set here as well, i.e.
//
//currentWeb.ApplyTheme("Default");
//currentWeb.RevertCss("");

            //Update the web with our restored defaults.
currentWeb.Update();
}

}

Now that we have the code, compile it to make sure that things are in working order.

We must sign the project so that it may be placed in the GAC.

Go to the properties of the project, and select Signing. Click on the checkbox to sign the assembly, select <New> from the dropdown. Now give it a name (temp), uncheck the password box and click Ok.  Back on the properties window, click save, and close the properties window.

Next we create a manifest file, and add some entries into it. (If you are lost here, go to my other blog post about deploying features.)

<Solution SolutionId="{NEW GUID HERE}" xmlns=http://schemas.microsoft.com/sharepoint/>

<Assemblies>

<Assembly DeploymentTarget="GlobalAssemblyCache" Location="LookFeelFeatureReceiver.dll">

</Assembly>

</Assemblies>

</Solution>

Finally, we need to add a cab file to hold the DLL and manifest.xml files so that we can deploy these to SharePoint.

(Also see the other blog post on this part if you are lost)

After a clean build, rename the cab to a wsp file, and copy to a SharePoint server.

Finally we are going to need to run some STSADM commands.

Stsadm.exe –o addsolution –filename LookFeelFeatureReceiver.wsp

Stsadm.exe –o deploysolution –name LookFeelFeatureReceiver.wsp –immediate –allowGacDeployment

The -allowGacDeployment is important here.

Well now that was not too difficult!  We have a feature reciever on the farm (SharePoint will pass this DLL out to all front end servers and place this file in the GAC.)  And now we can move on to creating a feature with a masterpage, cssFile, etc.

-Dan