Wednesday, May 28, 2008

CSS Stub for common Sharepoint 2007 and WSS v3 styles

After taking a look at Heather Solomon's awesome CSS Reference Chart for Sharepoint 2007 (with illustrations!), I though it would be a good idea to translate her hard work into a stubbed CSS document for use in my projects. Keep in mind that I haven't verified whether all of her styles actually do what they claim to do. I simply converted the table into a usable stylesheet. All you need to do is just fill in your custom style elements.

You can download the the stylesheet here[.css] or here[.pdf].

Friday, May 23, 2008

ERROR: Failed to create feature receiver...

I was working on a STSDev project which deployed a feature with a feature receiver. I had the feature working without the FeatureReceiver but as soon as I added the FeatureReceiver related attributes to my <Feature> element I got the following error:

Failed to create feature receiver object from assembly "Org.Project.Solution, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c632353d405b3209", type "Org.Project.Solution.MyFeature.FeatureReceiver" for feature 6a9b2358-ea4e-486d-a4e4-4f813c52ce88: System.ArgumentNullException: Value cannot be null.
Parameter name: type
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at System.Activator.CreateInstance(Type type)
at Microsoft.SharePoint.Administration.SPFeatureDefinition.get_ReceiverObject()

After much digging around I discovered that STSDEV's Solution config file refers to a namespace as well as the dll. My FeatureReceiver's namespace was not prefixed with the right namespace

So just be sure that your project conforms to the following:

SolutionName (default name of outputted assembly): Org.Project.Solution (Org.Project.Solution.dll)
FeatureName: MyFeature
FeatureRecieverName: FeatureReceiver (in FeatureReceiver.cs)

Feature Namespace: Org.Project.Solution.MyFeature
SolutionConfig.xml's SafeControl's Namespace Attrib: Org.Project.Solution
Feature.xml's <Feature> ReceiverClass Attribute: Org.Project.Solution.MyFeature.FeatureReceiver
Feature.xml's <Feature> ReceiverAssembly Attribute: Org.Project.Solution

Tuesday, May 20, 2008

SharePoint Features & Scopes Explained

This is a very good resource to use when defining your features and trying to understand what scope each one should be at:

http://weblogs.asp.net/soever/archive/2007/05/03/sharepoint-features-elements-scope-and-other-info.aspx

Thursday, May 15, 2008

STSDev & VSeWSS - "dogs and cats, living together"

Both STSDEV and VSeWSS are very useful tools that, in their own way, give you more simplified elegant development.

STSDEV is great in that it gives you a clean, class library project structure so that you have lots of control over your project. VSeWSS on the other hand is a customized solution template that allows you to automatically add in all the necessary files for common WSS elements (lists, content types, etc). I really like the ease of using VSeWSS, but I prefer the project structure of STSDEV. My solution is quite simple. Create your Solution with STSDEV (I usually start with a Empty C# solution with assembly) and then add in a VSeWSS project once you have the STSDEV generated solution open.

I basically just use the VSeWSS project as a file generator and once the files are created, I copy them over to the STSDEV project and begin customization from there. The only thing you really have to remember is to copy the Attributes.cs file from the Properties folder in the VSeWSS solution to the Properties folder in the STSDEV solution.

Of course, many people just have template files that they use, but this prevents me from having to go out to the file system to get template files.

Tuesday, May 13, 2008

STSDev 1.3 Released

I was in the process of blogging about creating workflow features in STSDEV (1.2) when I realized that STSDEV 1.3 is now released!

I'm going to redo my post using STSDEV 1.3 to see if it simplifies things.

Thursday, May 8, 2008

Getting Rid of Errors When Using WordPrint from the InfoPath SDK

I've been messing around with the WordPrint utility and when I reinstalled it I was getting a cryptic error:

Runtime Error!

Program:

This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.


When you first start using WordPrint, copy the following files to your %Windows%\system32 directory:

%Program Files%\Microsoft Office 2003 Developer Resources\Microsoft Office InfoPath 2003 SDK\Tools\WordPrint\WordPrint.dll

%Program Files%\Microsoft Office 2003 Developer Resources\Microsoft Office InfoPath 2003 SDK\Tools\WordPrint\ImageDecode.dll

%Program Files%\Microsoft Office 2003 Developer Resources\Microsoft Office InfoPath 2003 SDK\Tools\html2xhtml.dll

Then run the regsvr32 on each of these .dll's from the system32 directory.

Wednesday, May 7, 2008

Label Cloud

This has nothing to do with SharePoint but I thought it was pretty cool. Here's how I got the Label Cloud working on blogger.

Creating a Publishing Page Layout

This next tutorial will show you how to create a page layout. I have to admit that the bulk of the content of this tutorial comes from a tutorial written here, however, there are a few errors in the example code provided and also STSDEV requires a few minor changes as well to get everything working. In addition, I'll try to elaborate on a few more things so that you get a better understanding.

Now let's dig in.

Introduction

If you have no experience with page layouts (and Master Pages), I suggest you read the Page Layouts and Master Pages page on MSDN. In short, page layouts allow you to customize the layout and appearance of content and web parts of pages within a MOSS publishing site. These pages are stored in a special Master Page and Page Layouts document library. Pages that are based off these Page Layouts will be stored in a 'Pages' document library at the root of the site. The nice thing about using the publishing infrastructure is that it lets you save drafts of your page revisions and does versioning and check in/out, just like a normal document library.

In order to do this tutorial, you'll need to have the MOSS Publishing Infrastructure and MOSS Publishing features turned on at the site collection and site level, respectively (under site settings).

Step 1: Start with a new STSDEV Project

You don't necessarily have to use STSDEV to create this project, however you will have to manually manipulate your Manifest.xml and .ddf files to create a SharePoint solution for deployment, as well as execute the proper commands to install/deploy etc. If you want to do without STSDEV be my guest, you'll just have to know what you're doing.
  1. Open Visual Studio and run STSDEV.
  2. Create a new project as an 'Simple Feature Solution', I'll call it 'TestPageLayout'
  3. Make sure you create a FeatureReceiver with this project.
  4. Open the 'TestPageLayout' solution once it has been created.

Step 1.5: A little more info

We're going to create a custom layout page based on a content type and deploy it with a feature. We're also going to create a feature receiver class to create a new page in our 'Pages' library based on our new Page Layout. The following steps will provide the walkthrough for doing this.

STSDEV Automatically creates the feature.xml file as well as the FeatureReceiver.cs file for you

Step 2: The feature.xml file
  1. Open the 'Rootfiles' folder in your solution and ensure the following directory structure exists: 'TEMPLATE\FEATURES\TestPageLayout'
  2. Open 'feature.xml' and add to the <ElementManifests> section the following:

    <ElementManifest Location="SiteColumns.xml" />
    <ElementManifest Location="ContentTypes.xml"/>
    <ElementManifest Location="Provisioning.xml"/>
    <ElementFile Location="PageLayouts\CustomPageLayout.aspx"/>

  3. Next add the following to the <ActivationDependencies> node:

    <ActivationDependency FeatureId="F6924D36-2FA8-4f0b-B16D-06B7250180FA"/>
    </ActivationDependencies>

  4. There are a few key items in this file which need to be explored:
    • The 'ReceiverAssembly' and 'ReceiverClass' attributes of the <Feature> element refer to the Assembly that this project will generate and the Class name of the Event Receiver class we'll working with later on.
    • The <ElementManifest> and <ElementFile> elements refer to files that we will be creating in the next steps. *NOTE: If you hand-build your Manifest and .dll files (i.e. you aren't using STSDEV) you don't necessarily need the <ElementFile> referring to the .aspx page. Here's another blog post I wrote with some more information about that.
    • Finally, the 'ActivationDependencies' section includes the features that need to be activated in order for this feature to work. In this case the Publishing Infrastructure feature.
  5. Optional: You can change the Title of the feature or the Description if you like.
Step 3: Create the Site Columns file
  1. Within your 'TEMPLATE\FEATURES\TestPageLayout' directory, add a new xml file called 'SiteColumns.xml'
  2. Open the 'SiteColumns.xml' file, delete any existing markup and paste the following:

    <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <Field Type="HTML"
    DisplayName="Introduction"
    RichText="TRUE"
    RichTextMode="FullHtml"
    Required="FALSE"
    Group="Custom Page Column"
    ID="{89AEE769-5F51-4608-B389-50C1B36C4FA8}"
    StaticName="Introduction"
    Name="Introduction" />
    <Field Type="Image"
    DisplayName="WelcomeImage"
    RichText="TRUE"
    RichTextMode="FullHtml"
    Required="FALSE"
    Group="Custom Page Column"
    ID="{49500A41-5AD3-44b8-BC52-FF19B4AF4888}"
    StaticName="WelcomeImage"
    Name="WelcomeImage" />
    </Elements>

    This file defines two columns (Fields) that we will add to the content type (in the next step).
Step 4: The ContentTypes.xml file
  1. Within your 'TEMPLATE\FEATURES\TestPageLayout' directory, add a new xml file called 'ContentTypes.xml'
  2. Open the 'ContentTypes.xml' file, delete any existing markup and paste the following:

    <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <ContentType ID="0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF3900916CECA7C77446059633C4287903AA2A"
    Name="CustomWelcomePageTemplate"
    Description="Custom Home Page Template"
    Group="Custom Pages">
    <FieldRefs>
    <FieldRef ID="89AEE769-5F51-4608-B389-50C1B36C4FA8"
    Name="Introduction"
    DisplayName="Introduction"
    ShowInDisplayForm="TRUE"
    ShowInFileDlg="TRUE"
    ShowInListSettings="TRUE"
    ShowInNewForm="TRUE"
    ShowInEditForm="TRUE"
    ReadOnlyClient="FALSE" />
    <FieldRef ID="49500A41-5AD3-44b8-BC52-FF19B4AF4888"
    Name="WelcomeImage"
    DisplayName="Welcome Image"
    ShowInDisplayForm="TRUE"
    ShowInFileDlg="TRUE"
    ShowInListSettings="TRUE"
    ShowInNewForm="TRUE"
    ShowInEditForm="TRUE"
    ReadOnlyClient="FALSE" />
    </FieldRefs>
    </ContentType>
    </Elements>

    You should note that the FieldRef ID's value is the IDs of the Site Columns you created in the previous steps.
Step 5: The CustomPageLayout.aspx file
  1. In your feature directory ('TEMPLATE\FEATURES\TestPageLayout') create a 'PageLayouts' folder.
  2. In the 'PageLayouts' folder add an aspx page called 'CustomPageLayout.aspx'.
  3. Open 'CustomPageLayout.aspx', erase any existing markup and paste the following code:

    <%@ Page language="C#" Inherits="Microsoft.SharePoint.Publishing.PublishingLayoutPage,Microsoft.SharePoint.Publishing,Version=12.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" meta:webpartpageexpansion="full" meta:progid="SharePoint.WebPartPage.Document" %>
    <%@ Register Tagprefix="SharePointWebControls" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    <asp:Content ContentPlaceholderID="PlaceHolderPageTitle" runat="server">
    <SharePointWebControls:FieldValue id="PageTitle" FieldName="Title" runat="server"/>
    </asp:Content>
    <asp:Content ContentPlaceholderID="PlaceHolderMain" runat="server">
    <div>
    <div id="WelcomePageImage">
    <PublishingWebControls:RichImageField ID="RichImageField1" FieldName="WelcomeImage" runat="server"></PublishingWebControls:RichImageField>
    </div>
    <div id="WelcomePageContent">
    <PublishingWebControls:RichHtmlField ID="RichHtmlField1" FieldName="Introduction" runat="server"></PublishingWebControls:RichHtmlField>
    </div>
    </div>
    </asp:Content>

    Notice that this page contains two PublishingWebControls that have their 'FieldName' attributes set to the values that we defined in the <FieldRef> elements of the Content Type Definition file (ContentTypes.xml).
Step 6: The Provisioning.xml file
  1. In the 'TEMPLATE\FEATURES\TestPageLayout' directory create a new xml file called 'Provisioning.xml'.
  2. Open Provisioning.xml and erase any existing markup. Then paste the following code:

    <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <Module Name="PageTemplates" Url="_catalogs/masterpage" Path="PageLayouts" RootWebOnly="TRUE">
    <File Url="CustomPageLayout.aspx" Type="GhostableInLibrary">
    <Property Name="ContentType"
    Value="$Resources:cmscore, contenttype_pagelayout_name;" />
    <Property Name="PublishingAssociatedContentType"
    Value=";#CustomWelcomePageTemplate;#0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF3900916CECA7C77446059633C4287903AA2A;#" />
    </File>
    </Module>
    </Elements>

    Note the Property Name 'PublishingAssociatedContentType' refers to the ID of the ContentType we declared earlier.
Step 7: The FeatureReceiver.cs file
  1. In the root of your solution STSDEV should have created a FeatureReceiver.cs file. Open this file
  2. Replace the 'FeatureActivated' method with the following code:

    public override void FeatureActivated(SPFeatureReceiverProperties properties)
    {
    using (SPSite siteCollection = properties.Feature.Parent as SPSite)
    {
    using(SPWeb web = siteCollection.RootWeb)
    {
    if (PublishingWeb.IsPublishingWeb(web))
    {
    //Get references to the publishing site
    PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);
    PublishingSite site = new PublishingSite(web.Site);

    //ensure that the page isn't present yet (in case the feature was activated and deactivated)
    if (publishingWeb.GetPublishingPages()["Pages/welcome.aspx"] == null)
    {
    //Create the default page
    SPContentTypeId contentTypeID = new SPContentTypeId("0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF3900916CECA7C77446059633C4287903AA2A");
    PageLayout[] layouts = publishingWeb.GetAvailablePageLayouts(contentTypeID);
    PageLayout welcomePageLayout = layouts[0];

    PublishingPage welcomePage = publishingWeb.GetPublishingPages().Add("welcome.aspx", welcomePageLayout); welcomePage.ListItem["Introduction"] = "This is some introduction default text";
    welcomePage.Update();

    //Set the default page
    SPFile welcomeFile = web.GetFile(welcomePage.Url);
    publishingWeb.DefaultPage = welcomeFile;

    publishingWeb.Update();
    }
    }
    }
    }
    }

    In essence, when the feature is activated, this method will create a page called 'welcome.aspx' based on the Page Layout we created. It will then make the welcome.aspx page the default page for this site.
Step 8: Build and Deploy

Change your Build Configuration to BuildDeploy and build the solution.

Step 9: Test it out

If we've done everything right, we should be able to try out our feature.
  1. Go to the root web of your site collection and make sure the Publishing Infrastructure feature is turned on in the Site Collection Features, and that the Publishing feature is turned on in the Site Features.
  2. Activate the feature we created in the Site Collection features (since we scoped the feature at the 'Site' level...if we had scoped it at the 'Web' level, it would be activated from the Site Features).
  3. Go to the root of the site and see if everything worked correctly.
Debugging

This feature should work without any problems provided your SharePoint server is configured correctly and you followed the steps outlined. If you run into errors here's a for debugging with STSDEV.

Monday, May 5, 2008

A quick tip for Page Layouts with STSDEV

I plan to write a start to finish tutorial on using STSDEV to create a simple page layout and feature receiver, but I don't have the time to do it right now and I wanted to share this tip:

When you are creating a feature that contains a page layout and you want that page layout to be copied over to your server, ensure you include the .aspx page as an <ElementFile> element into your feature.xml file. If you are hand writing your own manifest, you don't have to do it, but if you want STSDEV to do it for you you'll need this element.

Debugging Your Assemblies Generated from STSDEV

If you've gotten sufficiently comfortable generating solutions with STSDEV, you've probably found that debugging doesn't seem to work. The reason is because the DebugBuild configuration is the only configuration that includes Debug code.

Here's how to set up your project so that you can debug the other builds:

Go to your Project Properties, click the 'Build' tab and turn on 'Define DEBUG Constant' and 'Define TRACE Constant'.

Then click on the 'Advanced' button at the bottom of the Build configuration screen and change the 'Debug Output' value to 'full'.

This tip came from the STSDEV discussion forum.

IIS Settings for WSS/MOSS

One of our Server Admins was asking about IIS settings to optimize WSS/MOSS performance. This blog posting is a pretty good starting place, as it gives pretty good descriptions for the settings that MOSS installation/configuration doesn't take care of for you.