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;
}

maandag 16 juni 2008

Persisting dynamic controls through postbacks (part 2 of 2)

Second way: Adding it through the ID's of the controls

This way is a lot easier than the first way of doing it. It's a way that I've learnt from a colleague of mine (Koen Roos - His blog can be found here: http://knrs.blogspot.com/ ).

This method is based on the ID's of the controls.
When you add your controls to the page, you have to save the ID of the control into the viewstate instead of the serialized control itself. 
During postback we read out the ID's of the objects and re-add new controls, but with the same ID's as the old controls.
ASP.NET remembers the properties of these controls et voila.. the controls are persisted.
This is especially useful for f.e. fileinputs, where you can't set the selected file property by code for security reasons.

Step 1: Add a new Label to the page
image
Step 2: Re-add these labels during postbacks in the OnLoad event

image

Done! :)

zondag 15 juni 2008

Persisting dynamic controls through postbacks (part 1 of 2)


Most people will have had this problem already: you add a controls dynamically to your page, for example by a button with in its onclick event handler this code:

image

When you try to execute this once it indeed adds your new label, but if you execute it multiple times you notice it doesn't add more than one label.

This is due to the fact that the control isn't rebuilt during the subsequent postbacks. So how do we solve this?

Todays article consists of two ways to keep your dynamically added controls through postbacks.

The first way - Adding the controls to the viewstate

The first way is to add your controls to the viewstate when you add them to the controls collection of the page, and extracting them back out of the viewstate during the OnLoad event of the page.

The problem with this approach is that the default WebControls shipped with ASP.NET are not marked as serializable, so it is not that straightforward to just add them to the viewstate. This is why we have to make a new version of the webcontrol we use and make it serializable ourselves.

Making a serializable Label

Note: this can be done to other WebControls aswell

To do this we make a new class named SerializableLabel that inherits from the Label class, implements ISerializable and is marked as Serializable by placing the [Serializable] attribute to the class.

image

In this class we create serialization function, where we place our text attribute into the SerializationInfo class. This way we are able to read it out later on in the deserialization contructor in exactly the same way.

Adding the serializable Label to the viewstate

Next we'll make our button to add a this label to the controls collection.
What happens here is:

- We get our list of serializable labels out of the viewstate
- We make a new serializable label and add it to this list and the controls of this page
- We save the updated list back into the viewstate of our page

image


Next when we load our page back in again we need to get all the controls that we dynamically created previously and add it back to the page.

image

This way every time a postback occurs the previously added labels are also re-added to the page.

donderdag 12 juni 2008

OpenXML Format SDK released

Microsoft just released the OpenXML Format SDK, this should make it easier to program for it.

The Open XML Format SDK is built on top of the System.IO.Packaging API and provides strongly typed part classes to manipulate Open XML documents.

To download: http://www.microsoft.com/downloads/details.aspx?familyid=8D46C01F-E3F6-4069-869D-90B8B096B556&displaylang=en

For an example what you can do with it: http://www.textglow.net/

zaterdag 7 juni 2008

Silverlight 2.0 Beta 2 released

Silverlight 2.0 Beta 2 is released today, you can find the new installation files here: http://silverlight.net/GetStarted/


The improvements that caught my eye are:

  • More built-in controls (no more separate assemblies for commonly used components, greatly decreasing loading time and size
  • Various improvements to the textbox: (snippet from ScottGu's blog)"Text scrolling with text-wrap, multi-line text selection, document navigation keys, and copy/paste from the clipboard are now supported.Beta2 also now includes IME Level 3 input support (including candidate window selection) for non-western character sets"
  • UI Automation and Accessibility:This allows screen readers to read SL2.0 apps, by the time of the final release of silverlight they promise to let every control be interpretable by screenreaders.There will also be support for high contrast scenarios.

Various media improvements:

  • Adaptive streaming: allows SL to adapt itself to the conditions of the end user. It is able to reduce the bitrate for slower connections and slower CPU's.
  • DRM (digital rights management) protection support.
  • Server side playlists

Enhanced networking support:

  • Cross domain sockets
  • Background thread sockets: Makes it so that the UI doesn't freeze while doing network transactions
  • Improved support for SOAP web services
  • Support for ADO.NET Web services (.NET 3.5 SP1, formerly known as Astoria)
  • JSON services support

For a more complete list go visit ScottGu's blog (http://weblogs.asp.net/scottgu/archive/2008/06/06/silverlight-2-beta2-released.aspx) or ofcourse silverlight.net

Have a nice weekend,

Jeroen

vrijdag 6 juni 2008

Adding a multi person select field to your fields.xml

While I was googling to add a multi person field to a feature I noticed quite a lot of problems of getting them to actually use multiple persons.
The solution to this is to set the attribute mult to true like this:

< Field
Type="UserMulti"
DisplayName="The display name"
Description="Your description"
Group="Custom Columns"
ID="{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
List="UserInfo"
MaxLength="255"
Name="NotificatieAan"
Required="FALSE"
RowOrdinal="0"
Mult="TRUE"
ShowField="ImnName"
SourceID="http://schemas.microsoft.com/sharepoint/v3"
StaticName="InternallyUsedName" />

Planning for sharepoint boundaries

I just wanted to point out a great article on the limitations of sharepoint found on technet:
http://technet.microsoft.com/en-us/library/cc262787.aspx

Thanks to Bart for pointing this out for me (http://bartvandenheede.blogspot.com/)!

One note I would like to add to to the limitation of 2000 SPPrincipals (meaning either SPUser or SPGroups) per SPWeb. It isn't per sé wrong what they are stating there, but it should be 2000 principals per site collection.
The explanation for this is that each principle you add to a subweb automatically adds the principle to the rootweb, but with limited access.
This is to ensure that the principle has access to the subsite, but not to the sites above it.

If every site adds their principles automatically to the rootsite, the limit on the rootsite will quickly reach its limit of 2000.


Have a nice day,

Jeroen

donderdag 5 juni 2008

Problems assigning AD groups to sharepoint sites

While doing a project this week we got a really bizar issue that users couldn't acces their sites anymore.
The situation was as followed:
  • User user1 was in group group1
  • Web web1 had unique security (not inherited from its parent) and group1 had Read rights to that web

There was one problem though: every night there was as batch job that recreated all the AD groups for our company, instead of updating it.
This resulted in the groups still being added on the web, but the internal SID they referred to did not exist anymore.. thus blocking all the users from their sites.

Possible solutions:

  • Update the AD groups instead of deleting and recreating it prevents the problems from ever occuring
  • Update your security on the sharepoint webs through a timerjob after the AD creation batch has complete (not recommended!)