Navigation

Monday 22 December 2008

Delegate Controls - Why you need to delegate!

I wanted to introduce this topic before my break for the festive season, as I am going to be offline pretty much until a few weeks into 2009. And this topic is around the subject of Delegate Controls!

What are Delegate Controls?
Well .. delegates are basically a new control that can be used in SharePoint (both WSS 3.0 and MOSS 2007) which allow you to render different controls on different sites, using features to switch them on and off.

Sound interesting? Well let me whet your appetite further.

Apart from the fact that you can create your own delegates (hopefully your dev brain boggles already!) but Delegates are already in use in a large number of places in SharePoint:
  • Top Navigation Menu Control
  • Quick Launch Menu Control
  • Search Controls
  • My Links / Quick Links controls
  • etc ...
So .. in short, if you want to modify these controls you don't need to modify the master page.
I'll say that again, just in case you missed it. You don't need to modify the master page.

The delegate controls are already in the default.master, so you just need to install and activate a feature which tells SharePoint to use your custom control instead of the standard ones!

Neat huh? (I knew you'd like it)

So what kind of controls can I use with Delegates?
You'll like this answer too .... anything.

Yep, any control (either ASCX based user controls, or DLL based server controls) can be dropped into a delegate. All you need is a feature that registers it!

So how does it all work then?
Well .. delegates have 2 parts to them:
  • ASP.Net Delegate Control (effectively a placeholder)
  • Feature which registers a new ASP.Net control to use in place of the delegate
The structure of a Delegate Control is very simple:

<SharePoint:DelegateControl runat="server" ControlId="SmallSearchInputBox" />

You only have 1 attribute to worry about; ControlId is basically a unique "name" for your placeholder. The example shown here is for the standard Search control that appears on every page.

After you've got your Delegate Control, you need a feature to implement your actual ASP.Net controls. Luckily the feature is quite straightforward.

Example using Server Control
<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <Control
        Id="SmallSearchInputBox"
        Sequence="25"
        ControlClass="Microsoft.SharePoint.Portal.WebControls.SearchBoxEx"
        ControlAssembly="Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c">
            <Property Name="GoImageUrl">/_layouts/images/gosearch.gif</Property>
            <Property Name="GoImageUrlRTL">/_layouts/images/goRTL.gif</Property>
            <Property Name="GoImageActiveUrl">/_layouts/images/gosearch.gif</Property>
            <Property Name="GoImageActiveUrlRTL">/_layouts/images/goRTL.gif</Property>
            <Property Name="UseSiteDefaults">true</Property>
            <Property Name="FrameType">None</Property>
            <Property Name="ShowAdvancedSearch">true</Property>
    </Control>   
</Elements>
 
Example using User Control
<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/"> 
    <Control Id="CentralAdminLeftNavBarTop" Sequence="100" ControlSrc="~/_admin/configurationmonitor.ascx" />
</Elements>

The Id is the same as your "ControlId" property in your Delegate control. Then you either reference a set of Control Class / Control Assembly, or you point it to a relative path to the ASCX control using the ControlSrc property.

Thats it! Once your feature is activated (at whatever scope you choose ... Farm, Application, Site, Web) then your ASP.Net control will appear in place of the delegate!

But what about Sequence??
Ahhh ... well that is where the real beauty of Delegates comes through in a SharePoint environment! As the controls are installed and activated using Features, how do you account for having multiple features at multiple scopes?

The Sequence attribute allows you to offer a number value which will be used when choosing which feature has priority. Simply put, the feature with the lowest sequence number will be rendered.

This allows you to achieve 2 different things:
  1. Upgrade Path
  2. Different controls on different sites
In the example of an Upgrade path, take the example of the "SmallSearchInputBox" ControlId.

In WSS 3.0 this is implemented through a feature with a Sequence of 100. In MOSS 2007 Standard a replacement control was installed with a Sequence of 50. And in MOSS 2007 Enterprise another new control is implemented with a Sequence of 25!

Hopefully you can see the picture, but I'll join the dots anyway!

The same delegate, and the same master page is used in all 3 installs. But as you install a newer version, a replacement feature is activated (with a lower sequence number) which takes preference.

So .. if you wanted to replace the "SmallSearchInputBox" control in a WSS 3.0 system, but wanted the "out of the box" control to come back if they ever install MOSS 2007, then you could register your own feature with a Sequence of anything between 100 and 50.

This same approach can be used if you wanted to replace controls on a specific site. So lets say you want to replace the Quick Launch navigation control in specific web sites. You could create a Web scoped feature, and activate it on those sites that you want to replace the Quick Launch in.

No Master Page, No ASP.Net Web Form dev ... easy.


Wednesday 3 December 2008

Joining Content & Code as a Solutions Architect! (on Monday)

Ok .. so here is another reason why my posts have been few & far between recently .. yep ... I'm moving on to pastures new, and Friday is my last day at Ratio One!

Thankfully I have not succumb to the dreaded "credit crunch" but have decided to take a fantastic opportunity to join the Solutions Team at Content & Code as one of their Solution Architects, helping to design and scope solutions, aiding the consultants and developers in their technical delivery, drive best practice in the business and also try to get more involved in the SharePoint Community.

What does this mean? Well, I will still be making the same blog posts, and be just as active on the MSDN forums (if not more so!). It also means you'll be seeing a bit more of me at the User Groups and community events around London (and possibly elsewhere in Europe?).

I would also like to take this opportunity to both thank Content & Code for this great opportunity, and also to thank Ratio One for their support over the past 2 (and a bit) years. I've certainly come on a long way since my first forays into SharePoint, and (generally) loved every minute of it!



Tuesday 2 December 2008

Creating "External" URLs in the Quick Launch menu

This post was prompted by the problems I've been having trying to get header nodes to be added to a site when it is provisioned, which have a custom URL pointing at a different site in the site collection.

Despite the NavBar element in the onet.xml having a URL attribute, this had no effect on my quick launch and it was always created using the current web's URL (i.e. on click it just took me straight to the current web site home page).

So, I embarked on a simple feature which I could use to create those navigation headers.

The code is pretty simple:

public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            // get the current "Web" object
            using (SPWeb web = (SPWeb)properties.Feature.Parent)
            {
                    // create the new navigation node
                    SPNavigationNode newNode =
                        new SPNavigationNode("Go to any sub site", "/anysite/anysubsite", true);

                    // add the node to the quicklaunch menu
                    web.Navigation.QuickLaunch.AddAsLast(newNode);

                    // save the changes
                    newNode.Update();
            }
        }

Now, the main thing to note is that when you create your SPNavigationNode object to use the true argument in the constructor!

This tells SharePoint that the URL is an External URL (and by External .. I mean "not in the current web"). If you don't set this then you will get an error telling you that the URL is invalid, or that the page/file cannot be found.

Even if the URL is a relative URL to the same site collection, you still have to set this value to true! Not entirely obvious that one, so one to watch out for.



Sad news ...

Sorry that my activity in the past week has been a bit poor ... but my mother-in-law died last week. I've basically been buried in the subsequent activities (funeral directors, coroner, registrar, church, etc) which was made much harder because my father-in-law is deaf and cannot use the telephone.

Funeral on Thursday .. hopefully be back to my old self by the weekend.



Saturday 8 November 2008

New (Old) Car !!

Yay ... I just bought me a new (old) car ..
Been needing a second car for a while (the Mrs always nicks my main car to drive to work everyday) and been needing a run-about to take rubbish to the tip and to get me to the train station and back :)

So .. got myself a nice little Ford Fiesta .. 1.3 engine, ABS, Power Steering, new CD player ... and only 70,000 miles on the clock (despite being over 10 years old). Not bad for only £700 (at least I think so). Very pleased with it :)

Thursday 30 October 2008

Adding FAVICONS to SharePoint

Ok .. I admit it .. this isn't really just a SharePoint thing, it's a "web" thing, but quite frankly I am astounded that this isn't something provided out of the box.

So what are these favicon things anyway?

Favicons are the icons that appear in your web browser when you are surfing. They usually appear in the address bar (depending on your browser) and were originally created for older IE environments to help identify web sites in the Favourites folder (hence the name "favicon" = "favourites icon").

example favicons

Ok, thats great, so how do I get them in SharePoint?

Well, it's really quite simple. Favicons are represented by small "link" tags in your HTML. In SharePoint the most sensible place to put them is in the Master Page. The reason for this is that (generally) your Master Page is rendered for pretty much every page .. therefore you don't have to add favicon links all over the place.

All you need to do is put a "link" tag into your Master Page, within the "<head>" tags (i.e. it needs to be in the page header!)

<link rel="shortcut icon" href="/Portal Images/favicon.jpg" />

How to "SharePoint'ise" it!

I know, that's not a real word, but the best approach you can take is to place your icon image (either an icon or image file) into an Image Library. You can then place a relative URL to a specific image in that image library, and it allows the content editors to upload a new favicon whenever they want :) (with the same version control and content approval you would normally have).

Thats exactly what I did with the sample line of code above, with a file called "favicon.jpg" which is located in an Image Library called "Portal Images" at the top level of the site collection.

Now, if you want to get REALLY fancy, then you could change it to be relative to the Site Collection (so each site collection could potentially have a different favicon). Do you that, just follow my earlier post on creating "Site Collection Relative URLs in MOSS 2007".

Neat eh?



Wednesday 29 October 2008

Word, Excel and PowerPoint running from the browser .. it must be Office 14 for Web

This is a great "first look" video from Channel9 (http://channel9.msdn.com/posts/PDCNews/First-Look-Office-14-for-Web/) showing off the new browser based features of the Office 14 for web (still in beta, still in development!) at this weeks PDC!

It's hot off the press, and it's going to blow your socks off!

According to the video they have made heavy use of Silverlight and AJAX to create rich office clients that run through a web browser. Due to the user of Silverlight the rendering is crisp and detailed, and to be honest I couldn't tell the difference between the web version and the desktop client!

Multi-User editing (including from the browser!) allowing multiple users to edit the same document at the same time is demo'd, including talk about integrating better collaboration tools!

To get you even more excited, the web browser based application is demo'd from FireFox! That's right, the new Office 14 apps are being designed with complete and total cross-browser compatibility.

Excited about the next version of Office?? (i.e. SharePoint!!!) I am!



Thursday 23 October 2008

Blank "Web File Properties" when saving document from Word 2003

This is a problem that I encountered with a MOSS 2007 system that was upgraded from SPS 2003.

Specifically, we were developing a custom document library, and found that if we had libraries with multiple content types, when we tried to save documents from Microsoft Word 2003 the "Web File Properties" dialog (the pop-up window that asks you for metadata before the file hits the document library) was completely empty.

None of the fields were visible, not even the Content Type drop-down box!

Well, It seems that this problem is documented and known about, and there is a Microsoft Hotfix available (upon request).

(KB934253) The Web File Properties dialog box displays incorrect properties for a document that is saved in a Windows SharePoint Services 3.0 document library - http://support.microsoft.com/default.aspx?scid=kb;EN-US;934253

The solution to the issue above has been included in to a hotfix, which you can get the information from the following KB article:

(KB934790) Description of the Windows SharePoint Services 3.0 hotfix package: April 12, 2007 - http://support.microsoft.com/default.aspx?scid=kb;EN-US;934790

*files this one away for later*



Wednesday 22 October 2008

Medals in the MSDN Forums .. what do they mean?

If you are a regular user of the MSDN Forums then you may (or may not?) that each user is granted a number of "medals" (they used to be stars, for the old timers).
Well, I've taken a sneak peak through the members list, and deduced that medals = points.
 
Exactly how many points you have depend on a lot of things, including posts, answers, "helpful" tags and how "popular" your threads are.
 
I have got the following list though:
  • 0 Medals - 0 points (1 or 2 posts)
  • 1 Medal - 10 points (usually 1-5 posts)
  • 2 Medals - 750 points (roughly 30 "answers")
  • 3 Medals - 2,000 points (roughly 150 "answers")
  • 4 Medals - 7,500 points (roughly 300 - 500 answers)
  • 5 Medals - 50,000 points (roughly 1000 answers)

To find your own account (and how many "points" you have) you can use the search page.



Number of certified SharePoint Developers increase by 500% in 12 months ...

So demand slowly catches up with the market. Despite the credit crunch, and supposed "global economic recession", the SharePoint markets (and IT in general) continue to buck the trend.
 
 
There are now 2,360 MCTS WSS 3.0 Application Developers in the world. Last time I checked (about this time last year) there was less than 450! Not bad growth, I think.


The onet.xml order of execution (shown in 8 easy steps)

This post was prompted by a post in the MSDN Forums. Simply put … what order do things happen in the onet.xml?

This may seem like a trivial question .. but if you are writing custom features, it is important (to say vital) that you know whether or not your feature will activate before a list is created or after, or whether or not your files in modules will have been provisioned or not.

The order that I discovered is as follows:

  1. *<SiteFeatures> in onet.xml
  2. *Stapled Site Features (stapled using FeatureSiteTemplateAssociation)
  3. <WebFeature> in onet.xml
  4. Stapled Web Features (using FeatureSiteTemplateAssociation)
  5. <Lists> in onet.xml
  6. <Modules> in onet.xml

* note - obviously Site Features will only activate if you are creating a Site Collection, as opposed to a normal web site

How I worked this out

Well, you can copy the steps yourself, in 8 easy steps:

First off, create a new Custom Site Definition (a simple copy of STS). In my example, I called it MHSTS with a single configuration (#0) and created a WEBTEMP file to register it.

Second, create a new SPFeatureEventReceiver class (in an assembly from a class library). The code in the "FeatureActivated" should be something like this:

 
// this will let you check which feature is being activated .. so you can work out the order
string strFeature = properties.Definition.DisplayName;
 
// Add more code to check the SPWeb.Features, SPSite.Features, SPWeb.Lists and SPWeb.Files …
// this will tell you what has been created in the site, and what other features have been activated

Third, create 5 features (the scope is in [ ])

  • mhOnetSiteFeature [Site]
  • mhStapledSiteFeature [Site]
  • mhOnetWebFeature [WEB]
  • mhStapledWebFeature [WEB
  • mhManualWebFeature [WEB]

Each of these needs to be attached to the same SPFeatureEventReceiver class that we referenced earlier. This allows your debugger to work out which feature is activating … so each time your code steps into breakpoints, you can check the "Feature.Definition" properties and work out which feature is being activated.

Fourth step, create 2 more features which will act as Feature Staplers (using FeatureSiteTemplateAssociation elements).

  • mhWebStapler [Site]
    • Staples the mhStapledWebFeature to the MHSTS#0 template (when used to create a new Site or Site Collection).
  • mhSiteStapler [WebApplication]
    • Staples the mhStapledSiteFeature to the MHSTS#0 template (when used to create a Site Collection)

Fifth.. in your custom site definition (MHSTS) add the following features into the onet.xml:

  • <SiteFeatures>
    • mhOnetSiteFeature
    • mhWebStapler
  • <WebFeatures>
    • mhOnetWebFeature

Sixth; Install all of the features using STSADM, and (in Central Administration) activate the "mhSiteStapler" feature within a test Web Application.

Seventh; Within that Web Application, create a new Site Collection using your new site definition (MHSTS). This should fire off all of your features in the following order;

  1. mhOnetSiteFeature
  2. mhStapledSiteFeature
  3. mhOnetWebFeature
  4. mhStapledWebFeature

(you can check this by debugging your event handler, and setting a watch on the properties.Definition.DisplayName value)

Now .. if you are keeping a close eye on your debugging window, then you can also start to look at the state of the SPWeb itself. The main thing is that None of the Lists or pages will have been created … at ANY point in this process. This means that <Lists> and <Modules> will not be executed until ALL of your features have activated.

Eighth; Now you can double-check the theory … navigate to your new Site Collection .. and activate your remaining feature manually (mhManualWebFeature).

You should still have your debugging window open .. which should let you know that now (after the site is provisioned) all of the Lists and web pages are now accessible from Code.

Ok .. that's great … errrr … so What ??

Well, this has quite a lot of importance for writing custom features. If you want to write features which automatically manipulate pages and lists then you are going to be a bit stuck, as the lists and pages won't have been created until after your feature activates! (bummer eh? But what you gonna do?)

To get around this problem you really have 2 options:

  1. Make your own custom definition. Strip the lists out of the onet.xml, and create ListInstance Features. These can then be created during the feature activation stage, allowing them to be modified by other features that are being activated / stapled.
  2. Put some While Loops with Thread.Sleep() statements in your code, basically waiting until the lists have been created. This is not a very elegant solution but you don't have much choice if you are trying to use staplers to modify out of the box definitions (or if you don't want to touch the onet.xml).

Thats it ... comments welcome as always :)



Thursday 16 October 2008

How to check whether a user has completed a survey or not [MSDN Forum Post]

Spotted this one on the MSDN forums.
 
Describes code you can run to check whether or not a specific user has responded to a survey (great for those corporate compliance ones!)
 
You can read the full post here.


Wednesday 15 October 2008

Hiding Menu Items and Site Settings in SharePoint using Features

I have used the example of hiding the "Theme" button in Site Settings (as for corporate intranets with strict branding, this is quite a comment request. I would like to show you though how to not only hide specific menus, but how to hide whole sections of the Site Settings menu and other SharePoint menus too!

This all hinges on the HideCustomAction element which you can use in Features.

There are actually some pretty good (MSDN) references:

HideCustomAction - element

Default Custom Action Locations & IDs

How to: Hide a Menu Item in the ECB from SharePoint List Items

John Holliday - SharePoint Custom Action Identifiers

And a cross post, for completion:

How to: Add Actions to the User Interface

So What about this HideCustomAction thing then?

Ahhh yes, got carried away with MSDN references …

First off, you will need a feature (scoped at the Site Level)

Feature File (Feature.xml, don't forget to put your own GUID value in)



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



<Feature Id="GUID" 
    Title="Hide UI Custom Actions"

    Description="This example shows how you can hide menus inside Windows SharePoint Services."

    Version="1.0.0.0"

    Scope="Site"

    xmlns="http://schemas.microsoft.com/sharepoint/">

  <ElementManifests>

    <ElementManifest Location="HideUICustomActions.xml" />

  </ElementManifests>

</Feature>



Elements File (HideUICustomActions.xml)







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



<Elements xmlns="http://schemas.microsoft.com/sharepoint/">



<HideCustomAction



Id="HideThemeLink"



GroupId="Customization"



HideActionId="Theme"



Location="Microsoft.SharePoint.SiteSettings"



</HideCustomAction>



</Elements>





That will give you a feature which will remove the "Theme" links from the Site Settings menu. Now, let me quickly walk you through what the element file is composed of (hopefully the Feature file should be familiar enough).



HideCustomAction – This element defines a new custom action which we want to hide.



Id – This is optional (but recommended), used to identify this specific "hide" action from others.



GroupId – This is the GroupId value for the Custom Action that you want to hide.



HideActionId – This is the Id value in the Custom Action that you want to hide.



Location – This is the location value from the Custom Action that you want to hide.



If you want to find custom actions (and therefore access all of these values) then simply open up the Features folder (..\12\Templates\Features) and do a search for the phrase "CustomAction" in the files. You should find all of the CustomActions that are provided out of the box, and subsequently the ability to hide them if you want to! Exactly the same thing applies to Site Settings, so if you wanted to hide (for example) the "Themes" menu then you can find the Custom Action in the standard "SiteSettings" feature.



Enjoy, and let me know how you get on!



Monday 13 October 2008

[Code Update] SDK and Microsoft Press Both Wrong?? Custom Fields in the schema.xml

UPDATE
For those who missed my original article (SDK and Microsoft Press Both Wrong?? Custom Fields in the schema.xml) , you can find it here!
 
I finally got round to posting the code that goes with this article ..
 
Please find below the details on code for an SPFeatureReceiver class, that will automatically push down changes from your Content Type Features
(you will need to attach the code to your feature using the ReceiverAssembly and ReceiverClass attributes in your feature.
 
The code needs to be created as a Class in a Class Library, with Microsoft.SharePoint.dll added as a reference, and then added as a Using statement in the class itself.
 
Code Sample
 
EDIT - Thanks to a quick spot from Nick's SharePoint blog, I have updated the code to match! Thanks Nick!
 
class
ContentTypeInstaller : SPFeatureReceiver
{
// CODE DESCRIPTION
// ----------------
/*
* This is a feature handler which should be paired
* with a content type feature.
*
* We have identified a problem with Content Types,
* where the content type site columns are not pushed
* down to custom list definitions, until they are
* "modified" first.
*
* This feature will interrogate all of the associated
* xml files that are attached to the feature.
* Once found, it will "modify" each of the custom fields
* that are referenced.
*
* This should allow list definitions to use the content
* type columns, without declaring them in the schema.xml
*/
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
using(SPSite site = (SPSite)properties.Feature.Parent)
{
SPWeb web = site.OpenWeb(
"");
// loop through each of the elements in the feature
foreach (SPElementDefinition element in properties.Definition.GetElementDefinitions(CultureInfo.CurrentCulture))
{
#region
Loop through feature elements
 
// retrieve the xml content for the feature element
XmlNode content = element.XmlDefinition;
// only continue if the element is a content type definition
if (content.Name == "ContentType")
{
// grab a new Content Type object
string strCTypeID = content.Attributes["ID"].Value;
SPContentType cType = web.ContentTypes[
new SPContentTypeId(strCTypeID)];
#region
Get FieldRef Order from Content type
// grab the original order, we will need this later
string[] fieldOrder = new string[cType.FieldLinks.Count];
int x = 0;
foreach (SPFieldLink fieldlink in cType.FieldLinks)
{
fieldOrder[x] = fieldlink.Name;
x++;
}
#endregion
#region
Add new columns to the content type
// loop through each sub-node in the Content Type file
foreach (XmlNode node in content.ChildNodes)
{
#region
loop through sub nodes
// only continue for
// the FieldRefs collection
if (node.Name == "FieldRefs")
{
foreach (XmlNode fieldRef in node.ChildNodes)
{
#region
Loop through FieldRefs
// only apply for FieldRef tags
if (fieldRef.Name == "FieldRef")
{
// get the FieldID and use it to
// retrieve the SPField object
string fieldID = fieldRef.Attributes["ID"].Value;
//SPFieldLink fieldLink = cType.FieldLinks[new Guid(fieldID)];
SPField field = cType.Fields[
new Guid(fieldID)];
// first we need to remove the fieldref
cType.FieldLinks.Delete(
new Guid(fieldID));
// and save, pushing this change down
cType.Update(
true);
// NOTE - this will NOT delete any content
// in existing lists!
// now add the field back in again
cType.FieldLinks.Add(
new SPFieldLink(field));
// and call an update, pushing down all changes
cType.Update(
true);
// NOTE - this is what adds the column to those
// lists who don't already have it.
}
#endregion
}
 
}
#endregion
}
#endregion
#region
Apply changes
// reset the field order
// it is possible that adding and
// removing fields would have
// affected this
cType.FieldLinks.Reorder(fieldOrder);
// force update of the content type,
// pushing down to children
cType.Update(
true);
#endregion
}
#endregion
}
}
}
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
}
public override void FeatureInstalled(SPFeatureReceiverProperties properties)
{
}
public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
{
}
}
Enjoy, and happy coding!


Friday 10 October 2008

Quick Tip - Site Collection Relative URLs in MOSS 2007

This is a nice quick one...

 

If you try to use normal relative URL paths, then you may run into a spot of bother when trying to call a URL path that is relative to the Site Collection, especially when you have multiple Site Collections in your web application:

 

http://RootSite/sites/ThisSite/

 

How do you make an URL that is relative to the "ThisSite" site collection?

 

Well, you could hard-code the URL prefix, but that doesn't really sit very well for most implementations, especially when using multiple-access mappings, you might have multiple URLs for the same site collection!

 

Alternatively, you can use the SPUrl function:

 

Code Sample:

This example code will take you to the Site Settings page for the current Site Collection.

 

<a runat="server" href="<% SPUrl:~SiteCollection\_layouts\settings.aspx %>">Go to Top Level Site Settings</a>

 

Note - You must use the runat="server" attribute, otherwise it will send the literal text of <% SPUrl ...%> instead of the desired relative URL!

Also, you will need to add a reference to the Microsoft Publishing Assembly in the header tags; for that, see this blog

 

Publishing Header Tags

Thanks go to Hannah Scott (and her subsequent source) for this blog post.

 

<%@ Register Tagprefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="PublishingNavigation" Namespace="Microsoft.SharePoint.Publishing.Navigation" Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="PublishingVariations" TagName="VariationsLabelMenu" src="~/_controltemplates/VariationsLabelMenu.ascx" %>
<%@ Register Tagprefix="PublishingConsole" TagName="Console" src="~/_controltemplates/PublishingConsole.ascx" %>
<%@ Register TagPrefix="PublishingSiteAction" TagName="SiteActionMenu" src="~/_controltemplates/PublishingActionMenu.ascx" %>



Thursday 9 October 2008

SDK and Microsoft Press Both Wrong?? Custom Fields in the schema.xml

Ok, so I think I've found something here. It relates specifically to Site Columns and Content Types, and how they can be applied to Custom List Definitions.

According to the latest release of the WSS 3.0 SDK (August 2008?) and one of the "bible" textbooks for WSS 3.0 development (Inside WSS 3.0 - Ted Pattison & Daniel Larson - Microsoft Press) there are a couple of questionable "best practice" methods that I wanted some insight on.

Personally, I think I've found quite a big oversight, which could be causing problems all over the shop.

The Big Issue (not the magazine!)
The question is around building a custom List Definition, in which you want to implement a custom Content Type (with custom Site Columns).

Now, both the SDK and the Inside WSS 3.0 book (along with many many other references I've seen, including people) state that if you have custom fields in your content type, then you have to add them to the Schema XML.

This has always struck me as very odd. I mean, you have to add all of that information already to your Site Columns (fields) feature .. right? So aren't you just copy-pasting the same info?

Also, if you try to do this through the user interface, SharePoint will automatically add all of the columns from the content type when you add it to the list ... so why can't it do that through CAML too ??

Well, I wasn't happy about this, and decided to try things a different way.

The Big Experiment (not the Discovery Channel)
I wanted to try and make a set of features that proved these statements wrong:
  • Site Column Feature (which declares a single, custom text field)
  • Content Type Feature (which declares a single Content Type, inheriting from Document, and includes my site column as a Field Reference)
  • Document Library Feature (declares a new custom document library definition. The only change is the Content Type and switching on "management of content types". The custom field is NOT added to the Fields section in the schema.xml)

TAKE 1 - As expected
I finished my CAML, installed my features and activated them in a completely new vanilla Site Collection.
My site column and content type both appeared on activation (as expected) and my new library definition popped up in the create menu (also as expected).

I then created my Document Library ... and ... <anti><climax>my columns did not appear in the library</climax></anti>.

This was, for the cynics among you, entirely expected. Microsoft themselves (through the holy scriptures of the SDK) have stated that this would happen.

But then things got interesting ...

TAKE 2 - The interesting result
Ok I thought ... what is going on behind the scenes? Somehow I need my Content Type to take preference over the schema...

I had a bit of a think (and probably scratched my chin a few times).. eventually I hit upon an idea (don't ask me how .. one of those late night coffee moments!)

I reset my environment (brand new, clean site collection) and re-installed and re-activated my features.

BUT .. this time, BEFORE I created any libraries I went to the Content Type Gallery and looked at my Content Type.
I clicked on my custom field (in the content type itself) and changed one of the values (I actually changed it into a required field) and hit the OK Button (note - the "push changes down to child content types" WAS selected).

I then backed out of those screens, and created my Document Library... and ... <surprise>my custom columns DID APPEAR!!</surprise>!

This was quite a shock .. I mean .. the Fields section in my custom document library schema is empty (apart from the fields that come out of the box).

I checked the library settings, tried uploading a file, and even checked the Document Information Panel in Word 2007. My custom field was there, with all the correct metadata.

Conclusion - (the important bit .. for those who bothered to scroll down)

My conclusion:

You do not have to declare custom fields in the schema.xml, as long as you manually update your content type before creating any libraries.

But that's not practical ... I have <insert huge number>'s of content types!
Well .. I hear ya.

I have just finished off a custom Feature Receiver which can be attached to any Content Type Feature as a Receiver Assembly / Receiver Class.

The code will (when the feature is activated) locate all of the Content Type elements in the feature, and do an initial "Update - push down changes" when the content types are first activated. (UPDATE code as been published to my Blog. See this article for details).

This is effectively the "magic bullet" I was looking for, and with this:

  • Custom Fields do not have to be declared in the schema.xml
  • Custom Fields can still be referenced in views, even though they are not referenced as Fields.
  • All column and meta data management can be developed in the Content Types and Site Columns

Comments / Discussions / <not>Flames</not> ...

all are welcome :)



Tuesday 30 September 2008

Evaluation Virtual PC images set to expire ...

One to punt over from the Microsoft SharePoint Team Blog.

Basically, if you are using this then it's going to expire ... TODAY! (bummer eh?)

But fear not ... another one has been published ... so download that and be merry instead :)


Monday 15 September 2008

what happens when you tempt fate ...

Ok .. so I'm back from holiday.

The weather was ... well what can I say.

I experienced very nice weather. 35 *C (90+ *F) pretty much every day, just not where I wanted it to be.

You see I should never have opened my big mouth and mentioned hurricanes. Why? Because I had a mandatory evacuation of the Florida Keys to thank for ruining my 2nd week on holiday :(

Oh well, 2 weeks in Orlando is a little bit too much for me (but at least the weather was good .. where I was staying at least!)


Thursday 28 August 2008

Holiday in Florida ... woot!

Yep. I'm packing my bags and off to Florida for 2 weeks.

Got a friend who is getting married in DisneyWorld (make of that what you will!!) Personally I'm looking forward to the 2nd week .. relaxation in the Florida Keys (assuming I don't get a hurricane to spoil my day).

ahhh ... beaches ... swimming pools .. and drinks with little umbrellas in them :)

Wednesday 27 August 2008

How to handle document retention and expiry in MOSS 2007 - Disposition Workflow and Expiration Policy

This is rapidly becoming a hot topic in Records Management with SharePoint, as organisations put increasing amounts of information into their SharePoint environments serious thought needs to be put into how that information should expire and (more importantly) what happens when it expires.

SharePoint has several solutions to these issues which, if configured correctly, can help pave the way to successful document expiration management.

The Expiration Management Policy
Information Management Policies are a new framework introduced in MOSS 2007, and allow specific "policies" to be applied system wide using Content Types, or to individual document libraries and lists.

One of the most popular policies in information management is the Audit Policy (which is vastly superior to version history, as it can track who has viewed, downloaded or deleted a document, as well as who has made changes), but another equally important policy is the Expiration Policy.

The Expiration Policy effectively allows you to specify the retention period for content. This is generally calculated from the created or modified date, although you can specify any formula (i.e. calculated fields) based on any date/time column value.

When a document "expires" you can then select from a number of actions: delete the item, perform another custom action (extensible through development) or start a workflow, and it is the latter that we will focus on here.

As mentioned, you can develop additional "custom actions" for the expiry Information Policy, which you can deploy as a Feature (there is a good article here and also a forum post discussing the options for this).

The Disposition Approval Workflow
The disposition approval workflow is designed specifically for document expiry, and has been designed with a very simple user interface.

When started the workflow creates a task, which is linked to the document. The task presents the user with the options of deleting the item, or keeping it, and the ability to add some comments. Completing the task will perform the appropriate actions on the server.

This basically gives you "out of the box" capability to have items which expire and then get (optionally) deleted upon expiry.

..

Now, I put my developer hat on and delved behind the scenes.

The Disposition Approval Workflow consists of a custom Task Content Type which is used for the task, and an InfoPath form which is used for the task edit form (via Form Services).

This gives us 2 options for replacing / extending the Workflow.

1) Create our own custom content type for the tasks. This allows us to attach event handlers and perform any custom operations when the tasks are created / edited / completed.

2) Create a replacement InfoPath form and use that for the task completion, perhaps with additional options (such as "archive" ?).

...

Either way, the out of the box options are quite extensive, and the Workflow / Content Type structure gives enough extensibility to provide almost any functionality for document retention.



Friday 22 August 2008

People search errors when My Site is running on SSL

This was a great gotcha that I picked up duing a client project handover.
They reported issues with search, and I found a load of errors in the crawl logs regarding accessing the mysite.

You will find that this issue occurs when you configure your My Sites to run under SSL (HTTPS), and the problem is that the People Search isn't really interested in the My Site content, it is actually interested in the Profile Database (which is another thing most people forget to switch on .. make sure your Profile Database has an import schedule setup!)

Basically, you need to set the Content Source URL to the following:
sps3s://<mysiteurl>/

So if your mysite is running under https://mysite.company.com/ then you need to set your Content Source URL to:

sps3s://mysite.company.com/
Personally I found this pretty confusing, so I actually  split out the Profile Database content into a separate Content Source, and configured the People Scope to only retrieve items from that specific Content Source.

Happy searching!

Update
Just a quick update, because this is another "People Search" problem. Even if you don't use My Sites, you should still switch on and use the MySite web application and settings (You can stop people from creating "My Sites" by disabling Self Service Site Creation at the Web Application level).

The reason is that the My Site web application is used for People Search URLs and will automatically dsiplay information from the Profile Database (which is basically the user's "public profile") even if they don't have a My Site created!


Tuesday 19 August 2008

How to access STSADM from any directory

This is a nice quick tip for the August holiday season.
 
Open up the following:
 
Start --> Control Panel --> System
system_dialog
 
 
This should open up the System Properties dialog.
 
Go to the Advanced Tab and click on Environment Variables.
 
environment_var
 
Find the variable called "Path" and append this to the end:
;c:\program files\common files\microsoft shared\web server extensions\12\bin
 
env_var_path
 
That should be it.
 
You may need to re-open ay Command Prompt windows before you can use this.
 
Now you can just call "stsadm.exe" from any command prompt window!
 
Note - If you find type "stsadm.exe" a bit laborius, try adding another one:
Name: STSADM
Value: stsadm.exe
 
env_var_stsadm
 
Hopefully you get how this would work


Monday 23 June 2008

The Key to successful SharePoint Projects

I got 3 words for you ...

Plan
Plan
then Plan some more ...


Ok .. so this isn't specific for SharePoint, all Software development projects are reliant on planning for successful execution (how can you know if you have delivered, if you don't know exactly what you are supposed to be delivering?) but SharePoint has this point in spades.

The first reason is Scaleability. SharePoint scales extremely well (up to 40TB in Lab Conditions according to the Microsoft SharePoint Team Blog). In fact there is an excellent Whitepaper recently available on this topic: SharePoint Server 2007 Scalability and Performance whitepaper.
However ... this level of Scaleability can only come if it has been planned for. You cannot simply install SharePoint "OotB" (Out of the Box) and expect it all to work.

The main effort required in the Scaleability process is the idea of "Site Collections", each of which is reported to scale easily up to about 50GB (although the labs mentioned above had >100GB Site Collections). Either way, if you are looking at an enterprise level implementation you are probably going to run out of space at some point and that will cause problems.

So .. you need to factor in Site Collections to your infrastructure. I won't spend ages talking about them, but there is a great article by Hiran Salvi on Sites vs Site Collections that is a must read on the topic.

The other main factor is Content & Metadata Maintenance (also sometimes referred to as "Metadata Governance"). If you have been working with SharePoint for a while then you are bound to come across a client who asks the following:
 "Can I add a column to all of my Document Libraries?"

Now ... if you haven't planned for Content Types then this could be a really big headache! Content Types are effectively the schemas that define all of your SharePoint storage. Each time you create a Document Library it is using the OotB "Document" Content Type. Now .. you could go and just modify the Library itself, but then you are effectively breaking your Content Type structure and that is bad mojo! (what happens when you want to modify said column after you've added it to 50 libraries?? you'll need more than one cup of coffee for that job!). The main problem is that you cannot modify the "Document" content type either! (well .. you could ... but you will probably break something doing it!). The reason is that a lot of other places in SharePoint also use that Content Type (such as "Master Page Gallery" and "Page Libraries" to name but a few!). A second major problem is that you cannot easily modify all of the Document Libraries either! (I mean .. thats what Content Types are for .. right?)

The recommended practice is to create a custom Content Type for all of the user-created Document Libraries. If the client wants to add a column .. no problem, you just add the column to the new "custom" content type, and Robert's your father's brother!

Of course .. if you didn't plan for that in the beginning ... well .. you'll be in for some pain! You either have to pay a temp to sit on your server for days on end re-allocating all of the Content Types system wide, and then you still haven't solved the problem of new lists and libraries that keep getting created! Or you have to get a developer to spend some very expensive days writing code to go around and do it all automatically!

.. either way .. best to be avoided and will be far cheaper in the long run if you plan for it!

The final point on planning (and by no means the final word on the topic, just the final point in my ramblings) is the following:
Who is going to use the system? And how will they use it?

Far too many people assume that SharePoint, being a Microsoft product .. hmph .. will just work out of the box and will solve all their problems (including World Peace). The truth is .. SharePoint is an advanced and very very complex web development platform.
Yes, it provides a whole raft of management, maintenance and administration functions and offer variability and flexibility like few other web based systems before it! But it requires time, a LOT of thought and plenty of expertise to deploy correctly.
The most important part of this is the users. What business requirement is being satisfied? What is the reason for using SharePoint (or any web based system?), what are the problems and how has this implementation been designed to solve those problems?

Last but not least .. never never never neglect the end users, especially the Content Managers. I have seen 2 things commonly happen which cause projects to fail:
1) "We'll just give them all Team Sites"...
This is a classic. You create 500 Team Sites ... one for each department / user group / business stream / office / project.
There is one major problem. they are ALL EMPTY!
99% of users will load up their nice bright shiny portal ... and look at these nice big expensive blank pages. Then log off and probably never return.
If you don't give them content and relevant design then you won't get any buy in!

2) "We'll let the Site Owners do what they want ..."
This is probably worse that point (1). At least there you can rebuild and you don't have to worry about the current system (because it's pretty much empty .. right?).
Now don't get me wrong ... this technically CAN work .. but you need Effective Training to make sure that your Site Owners understand the followig ideas:
* How to manage content
* How to create a hierarchical structure that works
* How to manage security permissions
* What is vision for the system as a whole?
* What do we want people to use the system for?

Without a unified vision for the system you end up with an implementation that is haphazardly put together, where each site has it's own layout, classifications and web parts. Trying to central manage a system like that will be a nightmare .. for both the project leaders and the systems administrators!

Well .. thats my ramblings for now, hope some of these nuggets have sunk in.

As always ... comments welcome!

- Martin Hatch

Friday 9 May 2008

Talking about Microsoft Certified Professional Developer- Web Developer

Yay me... on Wednesday 7th May 2008 I passed the Microsoft Certified Professional Developer - Web Developer exam. Probably one of the hardest exams I've sat so far due to it being more conceptual (does this specification meet the requirements? … ) rather than technical (which class / method should you use for ..) kind of questions.

According to Microsoft I'm one of the first 5000 people worldwide to pass this one Open-mouthed

Hurrah ... now what's next ??



Wednesday 16 April 2008

Displaying an Access Report in a Web Part

ok .. so who uses Microsoft Access anymore ???
 
You might be surprised that the Report Designer is becoming increasingly popular now that the ability to link to SharePoint data has been added in. From any SharePoint list you should be able to select "Actions" and then "Open in Access" .. which then gives you the option of taking a copy of the data, or (even better) creating a link to the data in SharePoint (allowing you to report and query the SharePoint data direct from the SharePoint database!!)
 
This of course opens up the possibilities of non-technical end users creating rich reports using nothing more than Microsoft Access and a couple of out of the box web parts.
 
 
I must give a nod of thanks to the guys over at ProgrammingMSAccess, their samples on embedded Snapshots are the ones I am using in my web part.
So .. how can we get up and running?
 
First, add a Content Editor Web Part. Enter the following code into the Source of the web part (by modifying the web part, and using the built-in source editor).
<OBJECT ID="SnapshotViewer" WIDTH=800 HEIGHT=600
CLASSID=
"CLSID:F0E42D60-368C-11D0-AD81-00A0C90DC8D9">
<PARAM NAME="_ExtentX" VALUE="16722">
<PARAM NAME="_ExtentY" VALUE="11774">
<PARAM NAME="_Version" VALUE="65536">
<PARAM NAME="SnapshotPath"
VALUE=
"http://webserverURL/folder/snapshotfilename.snp">
<PARAM NAME="Zoom" VALUE="0">
<PARAM NAME="AllowContextMenu" VALUE="-1">
<PARAM NAME="ShowNavigationButtons" VALUE="-1">
</OBJECT>

The only part you have to change is the "VALUE" attribute for the "SnapShotPath" node (I've highlighted it for you to make it easy ;)). This needs to be a URL that points to the SnapShot file (preferably in a Document Library in your SharePoint Site - Anyone viewing this report will need Read access to it.).

That is pretty much all there is to it. Feel free to play about with the "Width" "Height" "AllowContextMenu" and "ShowNavigationButtons" ... I'm sure they are all pretty straightforward! ;)

One final note - All users who want to view the report must have Snapshot Viewer for Microsoft Access installed on their workstation (otherwise the web part will just be blank).

Example Report - Shown on a standard Web Part Page:

 Snapshot Image



SQL Server Feature Comparison (2005 – 2008)

This is something we've had under our hat where I work for a while.. as you should be aware if you do a "stand-alone" install of WSS 3.0 (or MOSS 2007) then it installs "SQL Express Edition" (a.k.a. MSDE) .. but this version does have some startling limitations!
 

SQL 2005 Feature Comparison

 

Express

Workgroup

Standard

Enterprise

Number of CPUs

1

2

4

No Limit

Max. RAM

1 GB

3GB

OS Limit

OS Limit

64-bit support?

 

 

X

X

Max. Database Size

4GB

No Limit

No Limit

No Limit

Clustering / Mirroring

 

 

X

X

Online Restore / Recovery

 

 

 

X

Management Studio

 

X

X

X

Job Scheduling (through Agent)

 

X

X

X

Import / Export

 

X

X

X

Web Services

 

 

X

X

 

Much more also available at Microsoft SQL Server 2005 Features Comparison.

 

SQL 2008 Feature Comparison

 

Compact

Express

Standard

Enterprise

Number of CPUs

1

1 (per server)

4

No Limit

Max. RAM

OS Limit

1GB

OS Limit

OS Limit

64-bit support?

 

 

X

X

Max. Database Size

4GB

4GB

No Limit

No Limit

Clustering / Mirroring

 

 

X

X

Online Restore / Recovery

 

 

 

X

Management Studio

 

(tool)

X

X

Job Scheduling (through Agent)

 

 

X

X

Import / Export

(tool)

 

X

X

Web Services

 

 

X

X

 

Detailed comparisons can be found between Compact and Express … and Standard and Enterprise