maandag 17 november 2008

Access denied while activating publishing features

Not so long ago I encountered a strange error on a sharepoint configuration: a site collection administrator was getting "Access Denied" errors while trying to activate the publishing site collection features.
As his account had nearly every security right available in that company (way too much) this error was very strange to get.
After some research I tried switching the application pool account of the portal to that of the central administration and apparantly this did the trick.

So the access denied was not received from the actual users account, but from the account the user was elevated to: the identity of the application pool (found in ISS > Application Pools > Your Pool > Properties > Identity).
My guess is that this account did not have enough access to the content databases to perform this action.

Note: This sharepoint configuration was installed by the book of the Microsoft configuration and I've heard other reports of configuration problems when doing this.
I'm no configuration expert so I don't know what right exactly was missing or where in this guide it is going wrong.

donderdag 6 november 2008

Using a centrally manageable custom masterpage

The standard microsoft way of deploying a custom masterpage is by making a custom provisioning feature that deploys your masterpage and all of its assets to the _catalogs/masterpages folder of your site collection.

Imagine if at the moment of deployment there is no certainty on how the masterpage will be in a certain amount of time and it is bound to change.

Are you going to manually deactivate and reactivate all these features or should there be another way?

Today I'm going to show you another way to centrally manage your masterpage so you only have to adjust it on one place.. you guessed it right: the layouts folder!

If you try to change one of the 4 masterpage tokens ( ~masterurl/default.master ; ~masterurl/custom.master ; ~site/custom.master ; ~sitecollection/custom.master) to a masterpage located in your layouts directory you get an error (the referenced file is not allowed on this page) telling you that this is an unsupported attribute.
Now how will we solve this issue? We will create a httpModule that will replace the masterpageurl in the pre-init event of the loaded page.

Step 1:
Copy your masterpage in your layouts folder (12/Template/Layouts/MyProject)

Step 2:
Create MasterPageModule.cs
> Let this class inherit from System.Web.IHttpModule
> Implement the Init() and Dispose()


public class MasterPageModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
}

void context_PreRequestHandlerExecute(object sender, EventArgs e)
{
Page page = HttpContext.Current.CurrentHandler as Page;
if (page != null)
page.PreInit += new EventHandler(page_PreInit);
}

void page_PreInit(object sender, EventArgs e)
{
Page page = sender as Page;
if (SPContext.Current.Web.WebTemplateId == 10001)
if (page != null)
if(page.MasterPageFile != null && page.MasterPageFile.ToLower().Contains("application.master"))
page.MasterPageFile = "/_layouts/CustomMasterPages/customApplication.master";
else
page.MasterPageFile = "/_layouts/CustomMasterPages/custom.master";
}

public void Dispose()
{
}
}

As you can see I use the PreInit event of the Page to change my masterpage to either the application masterpage or either the normal masterpage. I do this because the application masterpage needs to have 2 more contentplaceholders than in the regular default.master. For more information on this, take a look at Toms blog (references at the bottom of this post)
So what happens when we load a page: The page goes through its cycle and enters the PreInit fase, where this code kicks in and changes the masterpage accordingly.

Note 1: It isn't officially supported to change your default application.master
Note 2: It is possible that your Page already implements the PreInit. If this happens this code won't be run. F.e.: Most (if not all) publishing pages use the PreInit to change the masterpage to that of the currentWebs selected masterpage.

Step 3:
Strong name your dll, build it and put it in your global assembly cache (GAC)

Step 4:
Register your HttpModule in the web.config
Open your web.config and place the following line just before the </httpModules>:
<add name="MyModule" type="MyNameSpace.MasterPageModule, ##### Fully qualified name #####" />
To find your fully qualified name I would recommend using Red Gate's Reflector, I put the link to it in a previous post.

Step 5:
Enjoy.. that's all! Since we changed the web.config, doing an iisreset (or recycling the application pools) is not needed anymore. Whenever a change to the web.config is saved IIS does this automatically for you.

Note:
If you have pages made with the publishing contenttypes chances are very high that there will be an OnPreInit event already firing on the Page itself, thus overriding your own modules onpreinit.. be wary of this!

Some references on masterpages:
- http://jopx.blogspot.com/2007/09/ten-things-you-should-know-about.html
This is a good reference on masterpages in sharepoint in general, very recommended

- http://tomblog.insomniacminds.com/2007/10/29/sharepoint-branding-issues-application-pages/
A good reference on how to customize application masterpages

- http://support.microsoft.com/kb/307996
How to make a httpModule

maandag 3 november 2008

Handy sharepoint development tools

There are a few sharepoint development tools that I like very much.

I will list them here:
  • WSPBuilder Extensions (Visual studio addin)
    This tool allows me to deploy, upgrade and test my solutions faster.
  • Reflector (Red gate, previously Lutz Roeder)
    This tool allows me to reverse engineer dll's, especially handy for getting the fully qualified name of your dll's and also for reverse engineering sharepoint dll's to see how they do it.
  • Sharepoint manager 2007
    Handy tool to inspect properties / fields / folders through a winforms application. It's definintly easier than writing your own console applications ;-). I use this a lot for checking propertybags of which I am a huge fan.
  • IE Developer toolbar
    Addin to inspect your sites HTML and CSS. Used mainly for branding and updating masterpages / pagelayouts. Note: this is already embedded within IE 8 beta
  • Fiddlder
    Creates a proxy so you can see all the traffic sent. This enables you to find some bottlenecks like f.e. slow webservice

Have a nice evening!

How to read an SPUser field

Ok... it's been a while since I last posted, but to make it up I have prepared a few posts for the coming time. Ranging from making dependant caching mechanisms in sharepoint to creating custom httpHandlers to host your masterpages centrally.
But first.. a post that I have created in june *blush*, but still didn't post.

It's just a little snippet I like, but always have to write again. So I'm going to save it here on my blog so I never have to do it again... at least until I finally create an own framework ;-).

public static SPUser GetSPUser(SPListItem item, string key)  {
SPFieldUser field = item.Fields[key] as SPFieldUser;
if( field != null) {
SPFieldUserValue fieldValue = field.GetFieldValue(item[key].ToString()) as SPFieldUserValue;
if(fieldValue != null)
return fieldValue.User;
return null;
}