Considerations when referencing assemblies in your page layouts

This one came up in the office last week, and I thought it worthy of discussion. On one project we have, the page layouts use the ASP.Net Register directive to reference assemblies containing our controls. So we have several directives in the code similar to:

<%@ Register TagPrefix="psw" Namespace="OurCompany.OurClient.SharePoint.WebControls" Assembly="Parity.SharePoint.WebControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=00000000000000" %>

These serve the purpose of telling the page layout about our controls assembly, and ensuring the designer can supply us with Intellisense for the controls and their members.

The question which then arises is "what happens when we update the shared assembly and we want to increment the version number? Surely we don’t have to update and republish all our page layouts?" There are a couple of answers to this:

  • we could use assembly redirects in application config to avoid changing the page layouts. These entries would then tell .Net to load (for example) version 2.0.0.0 of our assembly whenever version 1.0.0.0 is requested. This would work, but would mean that we don’t get Intellisense for any new/changed members added in subsequent assembly versions.
  • we could also avoid referencing common assemblies in this way completely, and centralize the reference in web.config instead

So instead of having an entry in each page layout, the ‘Pages’ section of web.config (in .Net 2.0 and upwards) allows us to reference assemblies containing controls in one central place, meaning any changes to the assembly name are simple to implement:

<pages>
<controls>
<add tagPrefix="psw" namespace="OurCompany.OurClient.SharePoint.WebControls"
assembly="OurCompany.OurClient.SharePoint.WebControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=00000000000000" />
<!-- also works with short assembly name -->
<!--
<add tagPrefix="psw" namespace="OurCompany.OurClient.SharePoint.WebControls"
assembly="OurCompany.OurClient.SharePoint.WebControls" />
-->
</controls>
</pages>

[Side note] – as I specify in the comment, it is possible to reference the assembly with the short name, but shops with a defined versioning strategy will want to avoid this since it’s then not possible to have side-by-side versions of assemblies, one of the fundamental forward steps introduced with .Net.

However, it’s not all clear cut. Unfortunately SPD isn’t clever enough to resolve the assembly reference in web.config to provide Intellisense. I initially thought it was, but alas closing and re-opening shows that in fact something was cached. Visual Studio is sufficiently aware (if we were in a pure .Net scenario), but not SPD.

So it’s a trade-off as far as I can see – either have the @Register directive in your page layout (with version numbers in it), or reference in web.config but lose Intellisense.

I wondered if it was possible to use the short assembly name in the @Register directive, but supply a 4 part assembly name in web.config for use at runtime. Unfortunately this doesn’t work since .Net sees it as an ambiguous registration. So if you want to keep assembly version numbers out of your page layouts but keep Intellisense, one strategy could be to remove the @Register directives as part of your release process.

Or as an alternative final thought – which is more important, Intellisense during development or minimising running into this problem at release time? For my money, losing the inconvenience of Intellisense in SPD for controls in is a minor hassle, so referencing assemblies in web.config is a better approach.

Great controls to be aware of when building SharePoint sites

Something I’ve been meaning to do for a while is discuss some of the controls I’ve found useful when putting together SharePoint sites. Obviously before building a custom control for a specific behaviour, it’s a good idea to check if SharePoint comes with anything that will do the job. It sometimes surprising what you find! Certainly those from a Content Management Server background will be familiar with the idea of having lots of reusable controls (which used the CMS API) within the team, but in MOSS some of the equivalent controls come for free. The most obvious is the Content by Query web part (though we won’t mention that the output HTML isn’t accessible [WCAG AA-compliant] without extra work), but some of the smaller controls deserve some attention too. So here’s a rundown of some handy items for the toolbox:

SPSecurityTrimmedControl

This control can be used to selectively display content or controls depending on the current user’s SharePoint permissions. Whatever is the inner content of the control will therefore not be shown if the user doesn’t have the specified permissions. An example would be:

   1: <SharepointWebControls:SPSecurityTrimmedControl runat="server" Permissions="ManageWeb">
   2:     This is only visible to users who can manage current web..    
   3: </SharepointWebControls:SPSecurityTrimmedControl> 

In addition to the Permissions property shown above (enum), the PermissionsString property can be used to specify a comma-separated list of required permissions. This can be used in conjunction with the PermissionsMode property which takes ‘All’ or ‘Any’, and also the PermissionContext property which specifies what SharePoint object (e.g. ‘CurrentList’, ‘CurrentFolder’, ‘CurrentItem’, ‘CurrentSite’, ‘RootSite’) the specified permission applies to, so it’s flexible. Examples of the permissions which can be specified include ‘ManageLists’, ‘AddListItems’, ‘ViewPages’, ‘ManagePermissions’ and so on. These are members of the SPBasePermission enum and Zac Smith has a full list. Notably many of these permissions are probably more useful in a collab scenario rather than WCM. [UPDATE: Text in this section updated following comment below/further testing:] For WCM folks the control does look like it does something useful in being able to filter on authentication type – unfortunately this doesn’t work as advertised. For reference (in case MS fix it), the usage is:

   1: <SharepointWebControls:SPSecurityTrimmedControl runat="server" AuthenticationRestrictions="AnonymousUsersOnly">
   2:     This *should* be visible only to anonymous users but it doesn't work..    
   3: </SharepointWebControls:SPSecurityTrimmedControl> 

As you’d expect, valid values here are ‘AnonymousUsersOnly’, ‘AuthenticatedUsersOnly’ and ‘AllUsers’ – however as noted in the comments below ‘AuthenticatedUsersOnly’ is the only flag which seems to work properly.

There are some other interesting properties too:

  • PagesMode – valid options are ‘Design’, ‘All’ and ‘Normal’
  • QueryStringParametersToInclude
  • RequiredFeatures

These look like extra properties to filter on, but alas I couldn’t get these to work either. My investigative powers let me down here as firing up Reflector onto both SPSecurityTrimmedControl and the related RightsSensitiveVisibilityHelper class didn’t give anything away in terms of usage, nor did Google or searching the 12 hive. Certainly it looks like specifying values is all that would be needed for latter two parameters, but I had no joy. A final consideration for SPSecurityTrimmedControl however, is the idea of further possibilities opened by deriving from this control in the same way SPLinkButton does.

EditModePanel

Where the previous control examined the user’s permissions to establish whether content should be shown, the EditModePanel looks at whether the current page is in display or edit mode. This can be incredibly useful in the WCM world for displaying help messages or other content to users as they edit a page. However there are other uses – hiding navigation, adding inline CSS override classes to use different formatting (particularly useful) and emitting debug information in the HTML output are all examples. The declaration for this control would look like:

   1: <PublishingWebControls:EditModePanel SuppressTag="false" GroupingText="Title help" 
   2:         PageDisplayMode="Edit" runat="server" id="EditModePanel1">
   3:     Page titles should be concise
   4: </PublishingWebControls:EditModePanel>

At run time in edit mode, this would look like:

EditModePanel

A prettier usage might be to include the field controls within each respective EditModelPanel, meaning the input control is shown within the borders of the box. To do this we’d also need an extra EditModePanel set to PageDisplayMode="Display" which also contained the field control, since the original will display in edit mode only. Note this control will output a surrounding <div> unless the SuppressTag property is set to ‘True’.

ListItemProperty

One control you might use in conjunction with the previous control is the ListItemProperty control. This simple little fella allows you to write out a particular field’s value for a list item. The field which is rendered is specified with the Property attribute, where we specify the field’s internal name. By default, the current list item (i.e. for the page we’re viewing) is used, but this can be overridden by specifying the List property – to do this we specify the list GUID with braces:

   1: <SharePointWebControls:ListItemProperty runat="server" id="ListItemProperty1" 
   2:     List="{C110296D-2BE9-4818-80EE-A06BD018DE2F}" ListItemID="1" Property="Title"/>

I think of this control as doing a .ToString() on the contents of the chosen field. This can sometimes be useful in WCM where you want the value to appear in a different location onthe page to where it is edited – for example within a <title> tag. Note we can also specify the version of the list item we want to retrieve the value for with the ListItemVersion property.

ListProperty

Much the same as ListItemProperty except on a list itself. These two may well be used together as the code in a list’s DispForm.aspx does:

   1: <SharePoint:ListProperty Property="LinkTitle" runat="server" id="ID_LinkTitle"/>
   2: : 
   3: <SharePoint:ListItemProperty id="ID_ItemProperty" MaxLength="40" runat="server"/>

This will show the current list’s title, followed by a colon, followed by the current list item’s title.

ProjectProperty

Slightly confusing name, but this control allows us to write out some properties of the current site/web. The MSDN documentation shows the valid list to be:

  • BlogCategoryTitle – Category of the current post item
  • BlogPostTitle – Title of the current post item
  • Description – Description of the current Web site
  • RecycleBinEnabled – 1 if the recycle bin is enabled; otherwise, 0
  • SiteOwnerName – User name of the owner for the current site collection
  • SiteUrl – Full URL of the current site collection
  • Title – Title of the current Web site
  • Url – Full URL of the current Web site

So the following would write out the title of the current web:

   1: <SharePointWebControls:ProjectProperty runat="server" id="ProjectProperty1" 
   2:     Property="Title" />

DelegateControl

This control provides an architecture where an ‘outer’ control is added to the page layout/master page, but the ‘inner’ control is determined by a Feature, thus allowing the control to be swapped out without having to modify the original template. This is used widely in Microsoft’s master pages. This is a great control, I discuss it more fully in my Using the DelegateControl post.

AssetUrlSelector

To finish on something slightly different, this control can be invaluable when developing custom web parts and field controls. It provides the ‘file picker’ experience authors are used to when working with SharePoint, and fits well when you have a control which requires a file to be selected. So in several of my controls I allow the user to override the XSL file used for formatting, and the AssetUrlSelector is added to the user control I use for the edit view of the control. This provides me with the ‘browse’ button which will launch the picker when clicked:

AssetBrowseButton 
Clicking the button then shows:

AssetUrlSelector 
The AssetUrlSelector provides a fairly good user experience, including opening the picker in the location of the currently-selected file if one exists, or defaulting to a specified default location if not. Along similar lines if you need to provide a slick experience to select an image is the RichImageSelector – this is the picker used by the RichImageField control.

Summary

So that’s some of the controls I’ve found useful. Obviously there are stacks more and the ones I did highlight can be used in lots of interesting ways which aren’t discussed here. But hopefully this does serve to remind you to check what’s in the box before spending time writing your own!

Part 2 : Blending publishing/collaboration functionality in SharePoint

A couple of months ago I wrote an article on some of the issues around building sites which are not pure publishing or collaboration solutions, but which mix features of the two. I mentioned at the time that I would follow up on these issues and any others we came across at the end of the project, so here it is.

As a quick recap, we said that characteristics of a site which blends publishing/collab features could be:

  • site has completely bespoke look and feel/navigation
  • users will work with document libraries, discussions, calendars etc.
  • site templates or definitions are used to create several sites with the same content/functionality
  • custom workflow is used to support a business process (other than standard content publishing), perhaps with InfoPath forms

    So let’s cover some of the issues you may face in projects like this:

    Look and feel of system pages

    This refers to the fact that whilst pages you create will happily use your custom master page, any ‘system’ pages in the ‘_layouts’ directory will not share this look and feel by default since they reference a separate master page, ‘application.master’, which is also stored on the filesystem in ‘_layouts’. Such pages are often seen due to the use of collaboration functionality in our site, examples being when a user uploads or edits metadata for a file, starts a workflow etc.

    In fact this turned out to be less of an issue than I anticipated because:

    • a quick test showed that the use of a HTTP module to switch the master page of these pages works fine. Several people have documented this approach, and I note that Ted Pattison has provided a Codeplex feature for those who would prefer not to write their own code for this. (N.B. though not strictly supported, the idea behind the HTTP module approach is that it is better than modifying files installed with SharePoint such as ‘application.master’, and can be disabled with a switch if we need to fall back in line with official support.)
    • our client decided this was a low priority item, that we may or may not deal with further down the line

    On this subject, I see that Microsoft have themselves released KB article How to customize application pages in the Layouts folder in SharePoint Server 2007 and in Windows SharePoint Services 3.0. Bizarrely, the proposed solutions are modifying the standard files but taking backups of the originals, or duplicating the ‘layouts’ virtual directory in IIS – the HTTP module idea is not mentioned. Without dwelling on this too much, this seems crazy to me and I’m not the only one. I still much prefer the HTTP module solution and will use this on my projects where it is required, though will be sure to regression test thoroughly.


    Use of InfoPath with forms authentication

    This is an interesting illustration of blending the two types of functionality – collaboration solutions may well use InfoPath for forms, but publishing sites typically use forms auth for a customized/branded login experience. Straight away we ran into problems using InfoPath with forms auth – essentially the link to create a new instance of an InfoPath form in a forms library would disappear (example link shown below [Windows auth enabled here]):

  • It took a while for me to track down that this is related to the ‘Client Integration’ switch in Central Admin. For a forms auth site, this gets set to ‘off’ by default, but defaults to ‘on’ for windows auth sites. Unfortunately, resolving the problem isn’t as simple as flicking the switch back, since what the switch does is remove certain links and disable ActiveX controls which integrate with the browser for link-handling. With the switch enabled again, the InfoPath link reappears on the content type, but when a link to say, a Word document is followed, the browser now shows the basic prompt to download or save the file. This means the more sophisticated ‘do you want to check out or open as read-only’ prompt is lost and users must work with documents offline and upload to SharePoint at the end of editing, rather than being able to save back directly to the SharePoint repository. In other words, unacceptable to most for a SharePoint 2007 collaboration solution.

    In the end I found others in the same position, but didn’t find a solution in a short timeframe. Microsoft support tells me “they were unaware of any instances of of these two features working together in this way”, so the disappointing conclusion is that these two bits of functionality don’t play well together. Our client thus decided to accept windows authentication (our authentication store was always going to be AD rather than SQL anyhow). However, I’m actually convinced it would be possible to get this working given more time – I think the way forward would be to amend the site design to have a link to the InfoPath form in the standard content of a page rather than relying on SharePoint to supply the link. The information supplied in How to: Use Query Parameters to Invoke Browser-Enabled InfoPath Forms would be used here. I’m sure this must be possible and others have done it, I’d be interested to hear from anyone who has.


    Overidden control not appearing on standard collaboration pages

    Our client had requested some customizations to the search box, and going through our bug list towards the end of development, I realised that our customized version was present on pages we had created, but not existing list pages such as [MyList]/Forms/AllItems.aspx or similar. This seemed strange given that all pages were using our custom master and shared the same header! Digging deeper, this is caused by the fact that SharePoint uses a delegate control to load the search box .ascx file, and to properly override the control across the site, we needed to create a Feature to specify that our .ascx file should be used in preference to the standard control. If we had directly replaced the existing control on the filesystem this would not be required, but when adding custom files in order to avoid modifications to existing files, this extra piece is required. One to look out for when building sites of this nature.

    Summary

    I read some blogs/discussion threads earlier this week which suggest customizing SharePoint in this way is nigh on impossible, but our project (and surely many others) prove this isn’t the case. As is often the case with such a functional platform, there’s perhaps a greater chance of success if you understand the nuts and bolts of what SharePoint is doing, but extensive customizations to collaboration-focused sites are inherently possible!