Friday, December 12, 2008

Calculated Column to Write out the Month

I have many many lists that I want to group by month based on their creation date (or other date column). In order to do I thought I'd have to add a calculated column and then add a horrific formula of nested IF's.

Thankfully this formula does the trick: =TEXT([Article Date],"MMMM")

Thursday, December 11, 2008

Web Services on your dev machine

If you've ever tried to create a web service using a SharePoint development machine (using Visual Studio), you'll recognize this error:

"Visual Web Developer does not support creating Web sites on a SharePoint Web server."

Arrgh.. so annoying. Luckily there's an easy workaround:

First, create a new web application in your webroot folder (probably c:\Inetpub\wwwroot) by creating a folder with explorer, and then application-izing it using the IIS Administration snap-in.

Then, go back to Visual Studio and re-try to create the web service (File->New Web Site) using the name from the folder you just created.

Tadaaaa...

Friday, November 7, 2008

Debugging features with STSDEV

I've been banging my head for a few days trying to debug a feature receiver that I built and deployed using STSDEV. After scouring the web I found lots and lots of questions, and typically the same, incomplete, answer. To get things to work, this is what I had to do:
  1. In VS2008, click on Project->Settings->Debug. When you get to the debug settings for your project, you'll notice each of your build targets in a dropdown at the top of the page. Select a target and then scroll and click the 'Advanced' button. By default, STSDEV doesnt generate a PDB for most of its build targets, so you'll want to change the "Debug Info" drop-down selection to "full". Repeat for each build target that you need debug info to be generated for (at least DebugDeploy and DebugRedeploy).
  2. Build and deploy your solution using one of the targets you changed above.
  3. Map a drive to \\machinename\c$\windows\assembly. This allows you to see the file structure of the GAC without the shell getting in the way.
  4. Copy your just-generated PDB file from the project directory to the GAC_MSIL folder in your new mapped-drive directory. You'll need to do this each time you build. *some people say this isnt necessary, however.
  5. Attach your VS debugger to the w3wp.exe process. If there is more than one instance of w3wp running, use 'iisapp' from the command line to get a description for each one. This will help you pick.
  6. Set your breakpoints. At this point the symbols for your assembly might not be loaded (you'll get the dreaded empty-circle breakpoint). Don't worry - VS will find them.
  7. Browse to your feature-activation system page and activate your feature.

Good luck!

Wednesday, October 15, 2008

System Pages Shortcuts

I recently found a list of SharePoint system pages that someone compiled, and thought "man, it would be nice to have these in IE as favorites". So... I put together a little vb script that adds them. Before you run the script, open it up and change the rooturl variable to point to your site collection. This only works for IE, of course.

download the script here

Friday, October 10, 2008

Do as I say, not as I do

After spending a looong time trying to figure out why my code behind for my page layout wasn't updating after making a simple change and doing an STSDEV Release build, I found out the hard way that you have to do a DebugBuild before you do a ReleaseBuild, otherwise it won't update the dll. Save yourself some frustration and add this to your list of todos each time you do a release in STSDEV.

Thanks to fellow SharePointers blogger Grant for providing with technical/emotional guidance as I troubleshooted this issue.

Friday, September 26, 2008

Getting the current position of a contentquery result

I am using a content query web part and want to have the first record appear differently than the other records that come after it. In order to do this you need something like the xsl position() function to determine if you are at the first element or not. You can't use position() from within your ItemStyles.xsl template though (it always returns a 1). So you need to make two quick changes to get this working.

First edit ContentQueryMain.xsl
  1. find the OuterTemplate.CallItemTemplate template
  2. Find this block:
    <xsl:when test="@Style='NewsCategoryItem'">
    <xsl:apply-templates select="." mode="itemstyle">
    [fix will go here]
    </xsl:apply-templates>
    </xsl:when>
  3. Add this to the spot I've indicated above:
    <xsl:with-param name="CurPos" select="$CurPosition" />
  4. Save ContentQueryMain.xsl

Now edit ItemStyles.xsl
  1. Add the following as the first item in your template:
    <xsl:param name="CurPos" />
Now you can refer to the $CurPos value whenever you need to do something different based on the position.

Thursday, September 25, 2008

SharePoint solution deployment getting stuck

I was deploying a solution into our production farm and found that after adding my solution and trying to deploy it (from Central Admin), the the timer job just got stuck on 'Deploying...'. I eventually discovered that one of our app servers had a problem with the Timer Service and shut down. I restarted the timer service and the solution finished deploying.

Now it's time to figure out why the Timer Job failed...

SharePoint VHD Expansion

In my experience, a typical standalone MOSS installation on a Server 2003 machine will use at least 12-14Gb of space, not counting any other add-ons you're using (antivirus, etc). Unfortunately for those of us who use Virtual Server/Virtual PC for SharePoint development purposes, the default drive setup is a fixed-size 16Gb IDE drive, which doesn't leave much wiggle room. If you, like me, saw the 16 gigs during the installation and said "oh, that should be enough", and are now eating your words, this post is for you.

Virtual Server/Virtual PC doesn't have a built-in way to resize .vhd files, but fortunately there are a few options available. Instead of using a somewhat pricey tool like Ghost, there are a few free alternatives. My favorite is appropriately named VhdResizer, and is available here [vmtoolkit.com]. After its installed, just point it at your old .vhd (shut down the vm first) and plug in the name/path of where you want the newer, bigger one. Allocating space for the new drive might take a while (particularly if you're using a slow usb drive). Hang on to your old .vhd, just in case.

After the new .vhd has been created we have to resize the partion to use the additional space. To do this, you'll need to fire up a command prompt and go to your Microsoft Virtual Server\Vhdmount directory. After you get there, use the vhdmount and expand tools and these instructions to resize the partition.

BTW, this applies to any .vhd file, but since most SharePoint devs use virtual environments, I thought I'd add it here to make it easy to find.

A few things to note: If you can't find the command line tools, you might have a older version of Virtual Server. Just upgrade to at least 2005 SP1 and you should find what you need. Also, you might ask why you can't just use dynamically sized disks when you create your VM. The answer is... you can, but they'll be slower. So if you're running your vm's from a portable drive or on a slow laptop hard drive, they'll be reeealy slow. Fixed-size disks will give you a slight speed boost.

Thursday, September 18, 2008

Publishing Page Layout DateTimeField formatting

I wanted to have my DateTimeField show up with a different format than the 'short date' value that it defaults to. Unfortunately you can't just add a date format string to a field property to make this work. I've seen a few alternative ways to do this involving extending the DateTimeField control. But I didn't like those options and felt the way I finally figured out was a little nicer (in my opinion).

Here's what I did:

1. Add a code behind page to your page layout and wire it up. If you don't know how to do this watch this short video by Andrew Connell. The 2nd part has to do with Page Layouts but you do the exact same thing as he does in the first part with the master page.

2. Add an 2 EditModePanels to your page layout like so:

<PublishingWebControls:EditModePanel runat="server" ID="DateEditModePanel">
  <SharePointWebControls:DateTimeField ID="ArticleDateControl" runat="server" FieldName="NewsArticleDate" />
</PublishingWebControls:EditModePanel>
<PublishingWebControls:EditModePanel runat="server" ID="DateDisplayModePanel" PageDisplayMode="Display">
  <asp:Label runat="server" ID="lblFormatDate" />
</PublishingWebControls:EditModePanel>

3. Add the following control references to your code-behind class

protected Label lblFormatDate;
protected DateTimeField ArticleDateControl;

4. Add the following code in your code behind page:

protected override void OnLoad(EventArgs e)
{
if (this.ArticleDateControl != null)
{
string dateString = "";
try
{
dateString = Convert.ToDateTime(this.ArticleDateControl.ItemFieldValue).ToString("MMMM d, yyyy");
}
catch
{
dateString = "";
}
lblFormatDate.Text = dateString;
}
}


5. Do the dance of joy.

Tuesday, September 16, 2008

Publishing Page Layouts and Images

I recently was working on a project and was trying to get a RichImageField in a page layout working. I ran into a speed bump which was my RichImageField was displaying the html markup for my image tag rather than the image itself.

After pouring over the internet, I finally got it to work after I realized that I didn't include the 'SourceID' attribute in my field columns (SourceID="http://schemas.microsoft.com/sharepoint/v3").

Thursday, September 11, 2008

Content Query Web Part

Sadly there is no built in cross-site list view web part. This seems like a pretty big oversight to me, but there are 3rd party tools that do the trick. However if you want that functionality from out of the box components you have to use a content query web part.

Using the content query part is fairly straightforward but there are two things you must remember:

  1. The columns you are filtering on have to be site columns
  2. If you find some of your list fields aren't available to your itemstyle.xsl, it's likely you'll have to modify the web part's xml. In order to do this complete the following steps.
  • Click the verb menu of the web part and choose to export the part to your file system
  • Open the .webpart file on your file system and find the 'CommonViewFields' property and add your field and its type.
  • Delete the old webpart from your page and reimport the webpart (click Add a web part to this zone then use the advanced settings to import, the import option is in the dropdown by the little triangle in the advanced settings)
  • Now your field will be accessible by itemstyles.xsl code.

Monday, September 8, 2008

Custom list with content type item check-in throws "Value does not fall.." error

When checking in an item in a custom list, I was being presented with the following error:

Value does not fall within the expected range. at Microsoft.SharePoint.SPFieldCollection.GetFieldByInternalName(String strName, Boolean bThrowException) at Microsoft.SharePoint.SPFieldCollection.GetFieldByInternalName(String strName) at Microsoft.SharePoint.SPListItem.get_MissingRequiredFields() at Microsoft.SharePoint.ApplicationPages.Checkin.OnLoad(EventArgs e) at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

After much head-scratching and nightmarish debugging, I found that the answer was very simple: Do not have the "Required" attribute set to true in your content type definition, but rather specify this in your custom list schema.

Hope this helps!

Thursday, September 4, 2008

Programmatically Update Page Layouts

I updated my page layouts that I deployed as a feature, but found that I could not overwrite the Layout File. The solution was to add a new page layout and then you would have to associate the new layout with every page on your site that used it.

Obviously with a site of any size you'd have a lot of manual work to get this done, so doing it programmatically makes for a much better (and thorough) approach. After you've got your new page layouts, you could do something like this (in your event receiver class):

public override void FeatureActivated(SPFeatureReceiverProperties properties) {
//replace current page layouts with new page layouts on all pages

SPWeb web = SPContext.Current.Web;

SwapPageLayout(web, "FullWidthContentWithTitleV1.aspx", "FullWidthContentWithTitleV2.aspx");
}

private void SwapPageLayout(SPWeb web, string oldPageLayoutName, string newPageLayoutName)
{
PublishingWeb pubWeb = PublishingWeb.GetPublishingWeb(web);

PageLayout[] layouts = pubWeb.GetAvailablePageLayouts();
PageLayout newLayout = null;
PageLayout oldLayout = null;

foreach (PageLayout layout in layouts)
{
if (layout.Name == newPageLayoutName)
{
newLayout = layout;
}

if (layout.Name == oldPageLayoutName)
{
oldLayout = layout;
}
}

DoPageLayoutSwap(web, oldLayout, newLayout);
}

private void DoPageLayoutSwap(SPWeb web, PageLayout oldLayout, PageLayout newLayout)
{
string checkInComment = "PageLayout Feature automatically updated this page layout";

if (PublishingWeb.IsPublishingWeb(web))
{
PublishingWeb pubWeb = PublishingWeb.GetPublishingWeb(web);



foreach (SPListItem listItem in pubWeb.PagesList.Items)
{
if(PublishingPage.IsPublishingPage(listItem))
{
PublishingPage page = PublishingPage.GetPublishingPage(listItem);
if (page.Layout.Name == oldLayout.Name)
{
page.CheckOut();
page.Layout = newLayout;
page.Update();
page.CheckIn(checkInComment);
SPFile pageFile = page.ListItem.File;

pageFile.Publish(checkInComment);

if(listItem.ModerationInformation.Status.Equals(SPModerationStatusType.Pending))
pageFile.Approve(checkInComment);
}
}
}
}

//visit children
foreach (SPWeb childWeb in web.Webs)
{
DoPageLayoutSwap(childWeb, oldLayout, newLayout);
}
}

Tuesday, August 26, 2008

The Case of the Missing Icons

In a recent attempt to add some new filetype icons to SharePoint, I stumbled across an interesting problem... duplicate entries in the icon lookup file (...\12\TEMPLATE\XML\DOCICON.xml) cause icons to disappear, with the alt text "Item Icon" in their place. In my case, I added a Photoshop (.psd) icon for some of our designers. But, just like this guy, I quickly realized that SharePoint already has one. A duplicate entry will break icons in lots of places (search, for example), so edit with care.

Unicode Reference

When using SharePoint sometimes you run into a URL with lots of unicode character markup. Here's a good reference so you can figure out what the h%65ck it all means.

Monday, August 25, 2008

List Types and Base Types

Here's a good reference that I've been using for the all the List Types and BaseTypes:

Wednesday, August 20, 2008

Bulk MySite Creation

Because SharePoint will display active links to MySites that might not exist, I was asked to "pre-create" all of the MySites before an upcoming rollout to prevent any confusion from "broken" links. I found a tool at codeplex called TIN that seemed to do what I needed, but it was a little clunky so I rewrote it. The new version is incredibly simple, but it might save somone some time so I thought I'd share. Basic features include:
  • Bulk creation of MySites for entries in the ProfileManager
  • Bulk deletion of MySites for entries in the ProfileManager
  • List profiles from the ProfileManager and whether they have a MySite
  • Robust logging and error handling
  • Save-to-File for log results
  • Multiple threads for long-running operations and smoother screen updates
The source code isn't so beautiful, but here it is. Feel free to make any changes you like, and let us know if it worked for you. Also, if you do make changes and want to share, just send it in and we'll post an update.

Here's a shot of it in action:

Note: Generating a large number of personal sites can take a while, so you may want to run this sometime off-peak.

Tuesday, August 19, 2008

"This solution contains no resources scoped for a Web application and cannot be deployed to a particular Web application." in STSDEV

I recently created a Web Part based on the STSDEV Web Part project and found it was very simple to use. I had another Web Part to create but this time I decided to go with the more generic 'Empty Solution' project just to ensure I wasn't getting lazy with all the stuff STSDEV does for me. The project built, and installed properly into the solution store, but doing a 'DebugDeploy' failed with an error.

I compared the two projects and they seemed to be configured identically. However upon further inspection, I found that the 'DebugDeploy' section of the Web Part Project (STS DEV generated) is different than the 'DebugDeploy' section of the empty solution. changing this line:

<Exec Command="$(STSADM) -o deploysolution -name $(PackageName) -immediate -allowgacdeployment" />

to:

<Exec Command="$(STSADM) -o deploysolution -name $(PackageName) -immediate -allowgacdeployment -allcontenturls" />

solved the problem.

NOTE: you'll also want to update the retract solution command to this:

<Exec Command="$(STSADM) -o retractsolution -name $(PackageName) -immediate -allcontenturls" ContinueOnError="true" />

Activating SharePoint Publishing Infrastructure Results in 'Access Denied'

I was getting a 'Access Denied' error when trying to activate the SharePoint Publishing Infrastructure feature. I found two solutions. The first involved changing the Application Pool that Central Admin ran under. The second, found here, simply involves running an STSADM command from the command line. In a production system, I'd say that the stsadm way to go (it's also faster).

Thursday, August 14, 2008

SharePoint Slow?

Joel Oleson's blog has a great post on dealing with the slowness on first page request we've all dealt with.

Web Part Styles

There are many examples of how to create a web part. However the best way to style web parts is not necessarily well documented, so I thought I'd offer up my approach and see what the community thinks.

Basically I create my web part as a feature in a solution. Then, if my web part generates any code that requires styling I add a .css file to my feature directory. Next I provision the stylesheet of my web part to a folder within my site's "Style Library". Finally I add the code into my web part to add the stylesheet ("<link>") link to the header of the page that my web part has been dropped on.

Most of the stuff is straightforward but here's how to provision a style sheet to the style library:

  1. Add a "provisioning.xml" file to your feature and reference it in the ElementManifest section of Feature.xml
  2. in "provisioning.xml" enter the following:

    <?xml version="1.0" encoding="utf-8" ?>
    <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <Module Name="JumpToItemDropDownStyles" Url="Style Library/en-us/Core Styles/WebPartStyles" Path="Styles" RootWebOnly="TRUE">
    <File Url="JumpToItemDropDown.css" Type="GhostableInLibrary" IgnoreIfAlreadyExists="TRUE" />
    </Module>
    </Elements>
And here's how to add your style sheet reference dynamically:

In your webpart code (I do it in CreateChildControls) add the following code:

try
{
ContentPlaceHolder header = (ContentPlaceHolder)this.Page.Master.FindControl("PlaceHolderAdditionalPageHead");
if (header != null)
{
CssRegistration cssControls = new CssRegistration();
cssControls.Name = "The Url To Your Provisioned CSS file";
header.Controls.Add(cssControls);
}
}
catch (Exception ex)
{
throw new Exception("CSS Registration Error.

details:
" + ex.Message);
}

Tuesday, August 5, 2008

WebPart Error: [ArgumentException: The serialized data is invalid.]

You may run into this problem. In my case I had a legitimate serialization error, but when I took out the offending code I was still getting the same error.

I found the solution is to close/readd the webpart to eliminate the error.

Thursday, July 31, 2008

A very nice tool

This CAML builder tool is pretty nice. If you're like me and haven't memorized the CAML spec, it's incredibly useful to test your query in this and then paste them into your code.

U2U CAML Query Builder

IMPORTANT NOTE: When using the trying to Query a list, remove the <Query> tags from the query otherwise the query wont do anything aside from return the whole list!!

Wednesday, July 30, 2008

Build a Standalone VM for MOSS Development (or WSS Development)

This post is a fantastic starting place for building your own developer VM with SQL Server, AD, Email, MOSS, and Visual Studio.

You should pretty much follow this verbatim, but here are a few points to make things go smoothly

  1. When Setting up SharePoint Search, make sure you include the Domain with the username (or you'll get a cryptic error)
  2. After setting up SharePoint Search, if you're installing MOSS, turn on all the other services except for the document conversion related services.
  3. If installing MOSS, make sure you create an SSP.
  4. Don't delete the default web application, just stop it. Chances are deleting it won't hurt you but there are a few things that could get screwed up if you totally delete the default web application (for more info see this post).
  5. Do yourself a favor and put STSDEV on there.

Tuesday, July 29, 2008

The call to SPSearchServiceInstance.Provision (server 'NTS499') failed. Setting back to previous status 'Disabled'.

I was creating a stand alone dev machine the other day and ran into this error. The simple fix is that you need to put in the accounts that the Search service will run as with their domain names. (E.g. DOMAIN\username, not just username)

Quick and easy...

Friday, July 25, 2008

Turn on anonymous access

In order to turn on anonymous access (I had to do it so my XML Web Part could use a list's RSS Feed as an XML source) follow these steps.

  1. Enable Anonymous access on your Web Application in Central Admin. Go to 'Application Management' and choose the 'Authentication Providers' link.
  2. Choose your authentication provider in the appropriate zone and check 'Enable Anonymous Access'.
  3. Go to your site and turn on Anonymous Access by going to 'Site Settings' then 'Advanced Permissions'
  4. If there is no 'Settings' option in your advanced permissions list, then your site is inheriting permissions, you can either stop inheriting by clicking 'Actions'>'Edit Permissions' (after which the 'Settings' option will show, or you can choose to turn anonymous access on at the parent's level by choosing 'Manage Parent Permissions'
  5. Once you have the 'Settings' menu, choose Anonymous Access and turn it on at the Site or List level. (For anonymous RSS you only need list level).

Using RSS and XML Web Part

I really like the XML Web Part because of its simplicity - take an XML data source, apply XSLT and have it pretty much whatever you want.

I was recently asked to create a jump-to-list-item dropdown box so that you could place the web part on any page and a user could select an item from that list from a dropdown and it would take them to the list item. Here are the steps that it took to create this using the out of the box XML Web Part.

  1. Turn on anonymous access on your list (here's how to do it)
  2. RSS Enable your list and then view the RSS Feed (you can do this through the list's Action menu)
  3. Place an XML Web Part on your page
  4. Modify the settings of the XML web part by pasting your RSS Feed URL into the webpart's XML Source attribute.
  5. Open the XSLT editor and place the following code:


    <?xml version="1.0"?>

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:template match="/">

    <select id="jumpDD">
    <option>
    Select
    </option>

    <xsl:for-each select="rss/channel/item">

    <option>
    <xsl:attribute name="value">
    <xsl:value-of select="link"/>
    </xsl:attribute>

    <xsl:value-of select="title"/>
    </option>
    </xsl:if>

    </xsl:for-each>
    </select>

    <input class='webPartJump' onclick="window.location.href=jumpDD.options[jumpDD.selectedIndex].value;" onfocus="this.blur()" type="button" value="Go" />

    </xsl:template>
    </xsl:stylesheet>

  6. *Optional: I did this for a Wiki Page Library so I wanted the wiki page to open directly instead of opening the item (which contained the page). In the RSS Settings for the list you can specify to open the document directly instead of going to the item.
There are tons of options with the XML Web Part. (I just wish you could use OWSSVR.dll to provide list XML for you, but sadly I don't think the XML Web Part will pass credentials).

...sounds like a project for the future...

Thursday, July 24, 2008

Email Enabled Lists

After lots of digging, I finally got incoming-email-to-list functionality working in MOSS. Take a look at Steve Smith's excellent tutorial on getting things set up here. I had several issues during my setup, but here are the highlights:
  • Get things configured first using a machine-name/sub-domain first (i.e. use email@servername.company.com instead of email@company.com)
  • The MS least-privilege configuration doesn't apply here - each web application with lists that you want to be email-enabled must use the same app-pool identity as Central Administration (i.e. the "farm account"). Note that you can (and should) still have separate app-pools, but they have to run using the same identity.
  • Don't forget to delegate control to the app-pool identity for making changes in AD. After getting frustrated I just granted full-control to the OU and then went back later and fixed it.
  • Make sure the Sharepoint Timer service is running, otherwise the emails will just sit in the maildrop folder on your SMTP server and they'll never make it to a list. Trust me.
  • I should be kicked for this... Make sure the user account that you are using to test actually has rights to post to the list. As far as I can tell, MOSS doesn't send you any sort of "post rejected" email to let you know, so you'll be chasing your tail. Again, trust me.

Tuesday, July 15, 2008

Create Custom Applications Pages

At some point, in your WSS or MOSS customization and development process, you'll likely need to create a Custom Application pages. Custom application pages differ from site pages in that they are compiled and not customizable by the user. (to learn more about application pages click here).

If you'd like another good sample project to work off of, check out the CustomApplicationPages download Ted Pattison Group's download section.

I'd also like to point out that Ted covers the specifics of this download in his book Inside Microsoft Windows SharePoint Services 3.0 which you can purchase in our SharePointers store.

Monday, June 23, 2008

SharePoint object disposal

Special thanks to Brian, who commented on our Creating a Page Layout posting. I had forgot to create a using statement to automatically dispose of SPWeb in my feature receiver. Brian referred me to another blog post which gives an excellent listing of disposal concerns and best practices for overcoming them in SharePoint.

I strongly encourage you all to review these and ensure you are informed on when and why you should dispose of your SharePoint objects.

Tuesday, June 17, 2008

Visio Stencil for SharePoint Customization

If you're trying to brand/customize SharePoint you might want to check this out. It's a stencil for Visio that lets you do your design without having to work in SharePoint, HTML, or a graphics program.

Wednesday, June 11, 2008

ERROR: Exception from HRESULT: 0x81070201

When using STSDEV to create a custom list as a feature, I had my solution deploying and my feature activating without a problem, but then when I created the list I got the error:

ERROR: Exception from HRESULT: 0x81070201

I looked through the log files and found that the Schema.xml file was not included in my feature manifest as an <ElementFile> element. Once I added this it fixed this error

Monday, June 9, 2008

Understanding Content Type IDs and a Reference

Microsoft provides a very thorough explanation of ContentTypes here but you may be left wondering what content types you can inherit from (or more likely what are their content type IDs) so you can build off of them. Well you can always go look at them in the 'ctypes' feature folder (that's the out-of-box feature that defines the WSS content types). It's available at under your 12\TEMPLATE\Features\ctypes folder in the 'ctypeswss.xml' file.

Otherwise you can just refer to this list I pulled together:

0x : System
0x01 : Item
0x0101 : Document
0x010100629D00608F814dd6AC8A86903AEE72AA : ODCDocument
0x010100B4CBD48E029A4ad8B62CB0E41868F2B0 : UDCDocument
0x010101 : XMLDocument
0x010102 : Picture
0x010104 : UntypedDocument
0x010105 : MasterPage
0x010107 : DocumentWorkflowItem
0x010108 : WikiDocument
0x010109 : BasicPage
0x01010901 : WebPartPage
0x01010A : LinkToDocument
0x01010B : DublinCoreName
0x0102 : Event
0x0103 : Issue
0x0104 : Announcement
0x0105 : Link
0x0106 : Contact
0x0107 : Message
0x0108 : Task
0x010801 : WorkflowTask
0x010802 : AdminTask
0x0109 : WorkflowHistory
0x010A Person
0x010B SharePointGroup
0x010C DomainGroup
0x0110 : BlogPost
0x0111 : BlogComment
0x0116 : FarEastContact
0x0120 : Folder
0x012001 RootOfList
0x012002 : Discuss

By the way, I got this list by copying/modifying the files I used in this post to refer to the ctypeswss.xml file instead of the field types file.

Great SharePoint resource for Developers

Microsoft has a 10 part lab series which introduces several fundamental development tasks using SharePoint 2007. In addition there's a link to a VPC download that you can use to do the work.

Check it out here

Friday, June 6, 2008

STSDEV and Visual Studio 2008

So we're upgrading to VS 2008 and, according to the configuration screen in STSDEV you can create STSDEV projects in .NET 3.0 for VS 2008. So we installed VS2008, added STSDEV as an external tool and created a test Workflow Project.

The project was created fine but when STSDEV tried to build the project it crashed. We eventually discovered that the error was related to the fact that STSDEV was creating the .csproj file with the following line:

<Import Project="$(MSBuildExtensionsPath)\Microsoft\Windows Workflow Foundation\v3.0\Workflow.Targets" />

instead of:

<Import Project="$(MSBuildExtensionsPath)\Microsoft\Windows Workflow Foundation\v3.5\Workflow.Targets" />

You can manually go into your .csproj file and change this and your solution should build.

We're looking into modifying the STSDEV code to rebuild the project so that it will do this automatically, but until we figure that out and get it blogged, here's your quick fix.

Thursday, June 5, 2008

Renaming a Sharepoint 2007 / WSS 3.0 Server

I recently needed to rename my Sharepoint development machine so I could move it into a new collaborative development environment (versus standalone in a workgroup). A little searching turned up this tutorial[www.jjfblog.com] from a while back, which worked with a slight modification. I have reposted the contents of the tutorial below, with a slight modification (see original post and comments for details).

Note: The new collaborative environment uses Team Foundation Server 2008, so look for a later post on collaborative Sharepoint development using TFS.


First: Change each alternate access mapping for your MOSS/WSS deployment in Central Administration
  1. Open Central Administration
  2. Click on the “Operations” Tab
  3. Click on the “Alternate access mappings” link under the “Global Configuration” heading
  4. Modify each mapping item to reflect your newly chosen server name, making sure to keep port numbers the same (this also include the mapping for Central Administration, don’t worry it's cool)
Second: Use stsadm.exe to invoke the “renameserver” command option
  1. Open a command prompt window and navigate to the folder where stsadm.exe sits. Normally “C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN”.
  2. Use the renameserver command as follows, replacing and with the new and old names of your server:

    stsadm -o renameserver
    -newservername
    <newname> -oldservername <oldname>

Third: Rename your Server via Change Name Operation in Windows Server 2003
  1. Now the last step is to simply right click on My Computer
  2. Open “Properties”
  3. Click on “Computer Name” tab
  4. Click “Change” button
  5. Input your new server name and reboot the server

[added by Sharepointers]
Fourth: Use stsadm.exe to invoke the "updatefarmcredentials" command option
  1. Open a command prompt window and navigate to the folder where stsadm.exe sits. Normally “C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN”.
  2. Type in the following command and press [enter]:

    stsadm -o updatefarmcredentials -identitytype NetworkService
Note: After the command completes, you may need to run iisreset, using the /noforce option.

Monday, June 2, 2008

Directory of public sharepoint sites

The people over at wssdemo have put together a nice listing of public sites that use WSS or Sharepoint 2007 to some degree or another.

So, if you're in the middle of a design-related mental block, these are a great for getting your mojo back.

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.

Friday, April 25, 2008

Adding a custom content type to a site definition

Today we'll be a adding a custom content type to our site definition we created in this post. The project that we're working with is an STSDEV project, so my project file structure reflects that. If you aren't using STSDEV you may need to make a few modifications. If you don't know what custom content types are, here's a good overview.

The content type we develop here will extend the Document content type. We'll call it a Project Proposal. Now let's get to work.

Step 1: Project Set up

Aside from basing this project on the site definiton I created earlier, we'll need to add the Feature folders that reflect the structure on the server.
  1. Right click on the TEMPLATE folder in your project and choose 'Add New Folder', name this folder 'FEATURES'.
  2. Then add a folder under 'FEATURES' called 'ProjectProposalContentTypes'.

Step 2: The feature definition file

Since we want to deploy this as a feature we'll need to create the feature definition file.
  1. Right click the 'ProjectProposalContentTypes' folder and 'Add a New Item'. Choose XML document and name it 'feature.xml'.
  2. Paste the following code into the 'feature.xml' file:

    <?xml version="1.0" encoding="utf-8" ?>
    <!-- _lcid="1033" _version="12.0.4017" _dal="1" -->
    <!-- _LocalBinding="" -->
    <Feature Id="BC91162B-EB3D-4412-BBE0-E5547CAB05CA"
    Title="Project Proposal Content Types"
    Description="Project Proposal Content Types"
    Version="1.0.0.0"
    Scope="Site"
    xmlns="http://schemas.microsoft.com/sharepoint/">
    <ElementManifests>
    <ElementManifest Location="contentTypes/columns.xml" />
    <ElementManifest Location="contentTypes/ctypes.xml" />
    </ElementManifests>
    </Feature>

    There are a few things to note:
    • You should put your own GUID into the feature 'ID' attribute (you can generate a GUID from the tools menu in Visual Studio, just make sure to use Registry format and delete the curly brackets)
    • In the <ElementManifests> node there are two <ElementManifest> nodes that refer to files that we haven't created yet. The locations indicate that they will be in the 'contentTypes' folder which will be in the same directory as the feature.xml file.

Step 3: The columns.xml file (The columns/'Elements' file)

To keep things organized, we'll be defining the columns in a separate elements file from the content type definition. We'll then refer to the columns from the content type definition file in the next step.

  1. Right click on your 'ProjectProposalContentTypes' folder and add a new XML document called 'columns.xml'
  2. Add the following xml to your 'columns.xml' file:

    <?xml version="1.0" encoding="utf-8" ?>
    <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <Field ID="7F80D077-A4FF-4ad0-8F21-432957A6E39C"
    Name="ProjectType"
    StaticName="_ProjectType"
    Group="Project Proposals"
    DisplayName="Project Type"
    Type="Choice"
    Required="True"
    Sealed="TRUE">
    <CHOICES>
    <CHOICE>General Software Development Project</CHOICE>
    <CHOICE>Web Development Project</CHOICE>
    <CHOICE>Systems Architecture Project</CHOICE>
    </CHOICES>
    </Field>
    <Field ID="DED5654C-975C-4278-B198-978CE295454A"
    Name="TimeEstimate"
    StaticName="_TimeEstimate"
    Group="Project Proposals"
    DisplayName="Time Estimate (in hours)"
    Type="Number"
    Format="FALSE"
    Required="True"
    Sealed="TRUE"
    />
    <Field ID="AB47551C-CF14-4823-849A-4BB6E834A3E7"
    Name="Rate"
    StaticName="_Rate"
    Group="Project Proposals"
    DisplayName="Rate (/hr)"
    Type="Currency"
    />
    </Elements>

    What does this all mean? The Field 'ID' attribute uniquely identifies each field with a GUID. The 'Name' attribute is the name of the field. The 'StaticName' is the internal name of the field (used when using the API to get the field value). 'Group' is the column group that the column belongs to. The 'DisplayName' attribute is the column name as it appears in the UI. The 'Type' attribute is the data type that is contained within the field. ALSO NOTE: I broke out the custom Field Definitions into a separate file (above), but if you wanted to organize your project differently you could put your field definitions into the ctypes.xml file.
Step 4: The ctypes.xml file (the content type definition element file)

This file is the main content type definition file. We'll add the fields necessary for this content type. We'll be including 2 kinds of Field References: one for the built in fields that come with SharePoint and one that refers to the fields we defined in the step 3, above.
  1. Right click on your 'ProjectProposalContentTypes' folder and add a new XML document called 'ctypes.xml'
  2. Paste the following code into your 'ctypes.xml' file:

    <?xml version="1.0" encoding="utf-8" ?>
    <Elements xmlns="http://schemas.microsoft.com/sharepoint/" >
    <ContentType ID="0x010100817535AA5D8F4d47BC9AAE0507E045E7"
    Name="Project Proposal Content Type"
    Group="List Content Types"
    Description="A content type for managing project proposals"
    Version="0"
    Hidden="FALSE"
    >
    <FieldRefs>
    <FieldRef ID="fa564e0f-0c70-4ab9-b863-0177e6ddd247" Name="Title"/>
    <FieldRef ID="52578FC3-1F01-4f4d-B016-94CCBCF428CF" Name="_Comments"/>
    <FieldRef ID="7F80D077-A4FF-4ad0-8F21-432957A6E39C" Name="ProjectType" />
    <FieldRef ID="DED5654C-975C-4278-B198-978CE295454A" Name="TimeEstimate" />
    <FieldRef ID="AB47551C-CF14-4823-849A-4BB6E834A3E7" Name="Rate" />
    </FieldRefs>
    </ContentType>
    </Elements>

    Things to note:
    • The ContentType ID attribute is the string "0x010100" followed by a GUID (with no dashes. This leading "0x010100" is important. (It specifies that we'll be extending a document content type) This number breaks down as follows (from left to right). 0x = system, 0x01 = item, 0x0101 = document. The final '00' before the GUID is a spacer.
Step 5: Test it out.

Make sure your build configuration is set for DebugDeploy (this is an STSDEV setting) and build the project. After the solution has built correctly, you should be able to go to your SharePoint site, choose Site Actions > Site Settings > Site Collection Features and activate your feature. Then you can see your new content type in the 'Site Content Types' area. Note that this content type is based on the 'Document' content type.

If you'd like to apply this content type to a list. Create a new document library. Go to the list settings for that document library and under Advanced Settings choose to enable content type manangement. Then, back on the list settings for that document library, choose to add a content type from the existing site content types. You should see your content type listed there.

Step 6: Add the content type to your site definition automatically

The steps described above basically explain how to create a Custom Content Type and deploy it as a feature, but since I'm building off my original project (if you haven't done it and want to keep up, go here) I want this feature to be automatically associated with my site definition I'm creating. Here's how:

  1. Open your onet.xml for the site definition
  2. In the <Configurations><Configuration><SiteFeatures> tag, add a <Feature ID='insert your feature id here' /> (if you scoped your Custom Content Type feature at the 'Web' level, you'd put the Feature tag into the <WebFeatures> tag (we had to scope at the 'Site' level because the feature is defining Fields).
  3. That's all you should have to do to get your custom feature auto activated on site creation.
  4. Now do a DebugDeploy (or ReDeploy) and test it out by creating a new site collection based on the site definition and checking the Site Settings page to ensure the Site Feature is activated.

Thursday, April 24, 2008

Creating and Deploying a Custom Master Page with STSDev

This is my second post on creating SharePoint solutions the easy way, with STSDEV. This time around I'll be enhancing my last post's project by adding a custom master page. This master page will start by using a base master page from Heather Solomon's site. If you don't already have it, download it.

The base master page simply gives you a stripped down master page that you can enhance. We'll actually do some enhancements to give a taste of the power that you have over the UI when you choose to customize a master page.

Step 1: Add the base master page to the project
  1. If you haven't already done so, download and unzip the base master page from Heather Solomon's site.
  2. Right click on your 'RootFiles\TEMPLATE\SiteTemplates\YourSiteTemplateName' directory and choose 'Add Existing Item'
  3. Select the base master page from your file system and click 'Add'
  4. Rename the file 'SharePointersDemoCustom.master'.
Step 2: Editing the Default.aspx file
  1. Open the default.aspx file
  2. At the top of the page, change the 'Page' directives 'MasterPageFile' attribute to '~masterurl/custom.master' (note that this value can only be 'default.master' or 'custom.master' but you can name your file whatever you like because the onet.xml file's <Module> element contains the reference to the actual file)
  3. Save the file
Step 3: Editing the onet.xml file
  1. Open the onet.xml file
  2. In the <ListTemplates> node add the following child node:

    <ListTemplate Name="mplib" DisplayName="$Resources:MasterPageGallery;"
    Description="$Resources:global_onet_mplib_desc;"
    SetupPath="global\lists\mplib" Type="116"
    BaseType="1" Path="GLOBAL" Hidden="TRUE"
    HiddenList="TRUE" NoCrawl="TRUE" Unique="TRUE"
    Catalog="TRUE" OnQuickLaunch="FALSE" SecurityBits="11"
    AllowDeletion="False" AllowEveryoneViewItems="TRUE"
    Image="/_layouts/images/itdl.gif" AlwaysIncludeContent="TRUE"
    DocumentTemplate="100" />

  3. Find the <Configuration> node the 'ID' attribute of 0 (zero)
  4. Add the 'MasterUrl' attribute to the <Configuration> node like so:

    <Configuration ID="0" Name="Blank" MasterUrl="_catalogs/masterpage/SharePointersDemoCustom.master">

  5. The <Configuration> node you just modified should have a <Modules> child element. Add the following <Module> tag as a child of this node

    <Module Name="CustomMasterPage" />

  6. Now go to the outer <Modules> tag that is a child of the main <Project> node and add the following child <Module> node

    <Module Name="CustomMasterPage" List="116" Url="_catalogs/masterpage" RootWebOnly="FALSE">
    <File Url="SharePointersDemoCustom.master" Type="GhostableInLibrary" IgnoreIfAlreadyExists="TRUE" />
    </Module>
Step 4: Deploy the project

Again, STSDEV makes this a breeze. If this is the first time you've deployed this solution change your build configuration to DebugDeploy and do a build, otherwise do a DebugRedeploy.

Now create a new site based on your site definition and see if your masterpage is working correctly. (Note, it should look pretty ugly since we haven't modified the UI yet.

Step 5: Start tweaking that master page!

Here's a bunch of really good resources for customizing your master pages all in one place. Heather Solomon really is the expert when it comes to SharePoint branding:

http://www.heathersolomon.com/blog/articles/sp2007.aspx

Wednesday, April 23, 2008

Deleting sites that were created with errors

This post will have something to do with my next post...

When you are creating site definitions and deploying them via a solution, you may successfully deploy them and then find out there is a problem with them upon creation, i.e. you get an error message when creating a site using the definition through the UI.

After the error occurs, the site may actually have been created, but does not show up in your navigation bar and the root of the site will be inaccessible. Interestingly enough, you can still get to the site's settings page by going to: http://serverName/siteName/_layouts/settings.aspx

You can then delete the broken site from there.

Using STSDEV to create a solution with a Site Definition

In this post I'll give a basic overview of how to create a simple site definition using STSDEV. The purpose of using STSDEV is to give the project a standardized structure and to make use of the solution autogeneration.

Here are the steps (Make sure you've downloaded STSDEV and run through the tutorials, or understanding this might be tough)

Part 1: Generate the STSDEV solution

  1. Open Visual Studio and run STSDEV (should be an option on your tools menu if you ran through the tutorials, see above link)
  2. Choose to create an empty solution with C# assembly
  3. Click 'Create the Solution'
  4. After you create the solution, you'll need to open it from the file system. STSDEV does not automatically open it for you in Visual Studio.

Part 2: Set up the project structure

Even the most basic site definition needs at least 3 files: a webtemp.xml file, an onet.xml file, and a default.aspx file. So let's create these files in the appropriate places.
  1. right click on the 'RootFiles' folder and add a new folder called 'TEMPLATE'
  2. Under the 'TEMPLATE' folder you created add a new folder called '1033'
  3. Under the '1033' folder you created create a new folder called 'XML'
  4. In the 'TEMPLATE/1033/XML' folder add a new XML file called 'webtemp.YourSiteName.xml', where your site name is what you want to call your site.
  5. Under the 'TEMPLATE' folder you created add a new folder called 'SiteTemplates'
  6. Under the 'SiteTemplates' folder create a folder called 'Your Site Name', with the name of the site you'd like to use.
  7. In the 'Your Site Name' folder, create a folder called 'xml'
Following those steps should set up your directory structure.

Part 3: The webtemp*.xml file

According to the MSDN documentation: 'The WebTemp*.xml files contain the site definition configurations that are available on the Template Selection section of the New SharePoint Site page'. So the details of this file determine how your site definition information will show up on the 'Create New Site' page.

  1. Go to the WebTemp.xml documentation page and copy the xml code into your webtemp*.xml file.
  2. Delete all the <template> nodes except for the first one
  3. In the only remaining <template> node, delete all the <configuration> nodes except the first one
  4. Enter a name for the <template> node 'Name' attribute (ensure this is the same name as your directory name in the SiteTemplates folder)
  5. Enter an id for the <template> node 'ID' attribute (if you've never done this before, start with 11001, this is because certain ID ranges are reserved. You'll notice that most of the out of the box templates are in the 10000 range, so hopefully anything in the 11000 range will be ok).
  6. Give the <configuration> node ID attribute a value of '0' (zero)
  7. Give the <configuration> node Title attribute a title of your choosing.
  8. Give the <configuration> node Description attribute a description of your choosing.
  9. Give the <configuration> node DisplayCategory attribute a category of your choosing (choosing 'Development' is a good idea, this will be the name of the tab on the 'Create Site' page that your site definition appears under)
Part 4a: Copying the onet.xml and default.aspx pages.

Since I will only be talking about the minimum needed to get your simple site definition working, after you complete this (or before) you might want to read up on the documentation for onet.xml

Because the onet.xml and default.aspx files are fairly long I won't post it here. What I do is use the version that is generated from VSeWSS. If you don't have this, download it because it is pretty useful, and generates solutions for you as well. I actually used this all the time before STSDEV came out and I decided that STSDEV generated what I considered to be cleaner and more well structured solutions. I have a template directory that contains most of the files that I use that I just copy into my solutions as I create them. I'll give the instructions on how to get the onet.xml and default.aspx file into your solution if you have VSeWSS v1.1 installed.
  1. Right click on your solution node for your STSDev Project and choose Add > New Project
  2. Choose 'Blank Site Definition' and create it
  3. In the project expand the 'Site Definition' folder and you'll see an onet.xml file, copy this to the 'TEMPLATE/SiteTemplates/Your Site Name/xml' folder in your STSDEV project
  4. In the same 'Site Definition' folder you found the onet.xml file in, you'll see a default.aspx file, copy this to the 'TEMPLATE/SiteTemplates/Your Site Name'.
Part 4b: Modifying the onet.xml file

There are only a few changes you need to make to the onet.xml file.
  1. Set the <project> node's 'Title' attribute to whatever you like.
  2. Set the <project> node's 'Revision' attribute to '1'.
  3. Set the <configuration> node's (under <project>) 'ID' attribute to '0' (zero).
Part 5: Deploy your solution

This is where STSDEV really shines, you basically don't need to do anything to get your site deployed other than select the 'DebugDeploy' configuration and do a build. If you did everything correctly you should be able to test your deployment by going to your site collection's home page and choosing Site Settings > Create and create a new site using your template.


Monday, April 21, 2008

Security issue when calling a WCF service from SharePoint

I've recently been charged with integrating several WCF services into SharePoint and it's been relatively smooth sailing up until I began to receive the following exception:

"The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate......."

My endpoint configuration originally looked like so:


<endpoint address="http://myserver/Services/BackOfficeService/basic"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IBackOfficeService"
contract="BackOfficeService.IBackOfficeService" name="BasicHttpBinding_IBackOfficeService" />

Looks ok, right?

Wrong! We are missing the 'identity' child of the endpoint element. So, to correct this issue, the final product should look like this:

<endpoint address="http://myserver/Services/BackOfficeService/basic"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IBackOfficeService"
contract="BackOfficeService.IBackOfficeService" name="BasicHttpBinding_IBackOfficeService">
<identity>
<userPrincipalName value="service@company.com" />
</identity>
</endpoint>

HTH,

Grant

Wednesday, April 16, 2008

STSDEV is pretty awesome, but...

I've begun using STSDEV as the start for my projects instead of VSeWSS. I like the simplicity of it, especially as Ted Pattison says in his first of three screencasts that you can load it into any installation of Visual Studio (that corresponds to the project type you created) because you don't rely on Add-ins/Extensions.

After running through the screencasts, I decided it was time to do the solution release build and I ran into immediate trouble with a "ERROR: Could not find file DeploymentFiles\SoulutionPackage.ddf ..." error message in the Output Window.

The solution, found on the STSDEV discussion board, is as follows:


  1. Modify the "ReleaseBuild" target in the DeploymentFiles\Microsoft.SharePoint.targets file as below (fix highlighted in bold red):

    <target name="ReleaseBuild">
    <message text="Deleting Pacakge File..." importance="high">
    <delete files="$(ProjectDeploymentFilesFolder)\$(PackageFile)" continueonerror="true">
    </delete>

    <message text="Building Cab File (Release Version)" importance="high">
    <exec command="$(MAKECAB) /F $(ProjectDeploymentFilesFolder)\SolutionPackage.ddf /D CabinetNameTemplate=$(PackageFile)" continueonerror="false">
    </exec>
    </message>
    </message>
    </target>



  2. Rebuild with the "DebugBuild" configuration
  3. Restart Visual Studio (to ensure nothing was cached)
  4. Rebuilt with the "ReleaseBuild" configuration

If you modify the Release Build configuration in the Microsoft.SharePoint.targets file right when you open the project for the first time after creating it in STSDEV it'll save you having to do the above steps.

ASP.Net AJAX and SharePoint

There's a project on CodePlex that integrates ASP.Net AJAX with SharePoint:

I've only read the overview, but I've had lots of projects that I've wanted to use AJAX with SharePoint. So I can see how this will be a tremendous help.

http://www.codeplex.com/sharepointajax

Sunday, March 23, 2008

Programmatically get SPList items from a SPView

Another tip that you're sure to find some use for:

Because SharePoint list (SPList) views (SPView) don't contain SPListItems or SPListItemCollections, if you want to programmatically retrieve list items from a list in the order specified by a view you've created you have to do it as follows (I've ommited, try-catch blocks and extraneous code to give you just the bare necessities)

SPListItemCollection coll = spWeb.Lists["ListName"].GetItems(spWebInstance.Lists["ListName"].Views["ViewName"]);


where spWeb is a SPWeb you've opened up from an SPSite object. and "ListName" and "ViewName" are the names of your lists and views, respectively.

Monday, February 25, 2008

Quick Reference for SharePoint Built in Fields

There are many instances where you need a quick, readable reference giving you the GUIDs for your FieldRef's in a content type definition file. Here's a handy xslt stylesheet that does the transform for you:

<?xml version="1.0" encoding="utf-8" ?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wss="http://schemas.microsoft.com/sharepoint/">

<xsl:output method="html" version="1.0" encoding="utf-8" indent="yes" />

<xsl:template match="wss:Elements">
<html>
<body>
<h2>SharePoint 2007 Built-In Fields</h2>
<table border="1" width="100%" style="font-size:10pt;">

<tr bgcolor="#9acd32">
<th align="left">Group</th>
<th align="left" width="100">Field</th>

<th align="left">Type</th>
<th align="left">Declaration</th>
</tr>
<xsl:apply-templates>

<xsl:sort select="@Group" />
<xsl:sort select="@Name" />
</xsl:apply-templates>
</table>

</body>
</html>
</xsl:template>
<xsl:template match="wss:Field">
<tr>
<td width="100"><xsl:value-of select="@Group"/></td>

<td width="100"><xsl:value-of select="@Name"/></td>
<td width="100"><xsl:value-of select="@Type"/></td>
<td>&lt;FieldRef ID=&quot;<xsl:value-of select="@ID"/>&quot; Name=&quot;<xsl:value-of select="@Name"/>&quot;/&gt;
</td>

</tr>
</xsl:template>
</xsl:stylesheet>



If you want everything done for you, save the above text into a file called "GenerateFieldDefs.xsl" and then save the below code into a document called "GenerateFieldDefs.html" and save both files into your SharePoint fields directory (..../12/TEMPLATE/FEATURES/fields). Then open the GenereateFieldDefs.html file with IE6 or Firefox 1.5 or higher.

Here's the html code:

<html>

<head>
<script>
function loadXMLDoc(fname)
{
var xmlDoc;
// code for IE
if (window.ActiveXObject)
{
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
}
// code for Mozilla, Firefox, Opera, etc.
else if (document.implementation
&& document.implementation.createDocument)
{
xmlDoc=document.implementation.createDocument("","",null);
}
else
{
alert('Your browser cannot handle this script');
}
xmlDoc.async=false;
xmlDoc.load(fname);
return(xmlDoc);
}

function displayResult()
{
xml=loadXMLDoc("fieldswss.xml");
xsl=loadXMLDoc("GenerateFieldDefs.xsl");
// code for IE
if (window.ActiveXObject)
{
ex=xml.transformNode(xsl);
document.getElementById("example").innerHTML=ex;
}
// code for Mozilla, Firefox, Opera, etc.
else if (document.implementation

&& document.implementation.createDocument)
{
xsltProcessor=new XSLTProcessor();
xsltProcessor.importStylesheet(xsl);
resultDocument = xsltProcessor.transformToFragment(xml,document);
document.getElementById("example").appendChild(resultDocument);
}
}
</script>
</head>
<body id="example" onLoad="displayResult()">
</body>
</html>