Saturday, February 28, 2009

How To Copy Permissions Between Site Collections

Hi again,

One of the more challenging issues in MOSS is permissions, specially if we need to move them between site collections.

To add permissions to item\folder\list\site we add SPRoleAssignment that contains SPUser (as SPPincipal), and SPRoleDefinition that contain the the BasePermissions or the Types (reader/contributor...).

Each role is have diffrent parameters in each site collection, for example my user can be in one site collection 1;#elad and in the other can be 5;#elad, the same user but a diffrent id. the same is for definition, contributor for example have the same base permissions in every site collection but have a differnt ID.

So what to do... ?

It is eazy, 
1. Create a new instant of your role user like this:

// role is the role assignment from the old site collection.
SPUser user = role.Member as SPUser;

2. Than create a new role assinment

// web is the site in the new site collection
SPRoleAssignment roleAssignment = new SPRoleAssignment(
                                   web.EnsureUser(user.LoginName) as SPPrincipal); 

Why EnsureUser ? 
The EnsureUser method will chack if the user exist in the corrent site and if not will create him as Limited Access permission. (10x to Michael Assouline that show me this method).

than add the role definitions to the new role assignment,

foreach (SPRoleDefinition roleDefinition in role.RoleDefinitionBindings)
{
// we cann't add Limited Access
if (roleDefinition.Type != SPRoleType.Guest)
        {
   definition = web.RoleDefinitions.GetByType(roleDefinition.Type);
   roleAssignment.RoleDefinitionBindings.Add(definition);
}
}

3. And now just add the new role to the item,

item.RoleAssignments.Add(roleAssignment); 


Friday, February 27, 2009

Wednesday, February 25, 2009

Update Moss Web.Config

1. Programatically using Sharepoint API

We can use SPWebConfigModification object like this:

This code update CustomErrors value

// Get an instance of my local web application
SPWebApplication webApp = new SPSite("http://localhost").WebApplication;
// Create my new modification to set the mode attibute to "Off".
// Example:
SPWebConfigModification modification = new SPWebConfigModification("mode", "system.web/customErrors");
modification.Owner = "SimpleSampleUniqueOwnerValue";

modification.Sequence = 0; modification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureAttribute;
modification.Value = "Off";
// Add my new web.config modification.
webApp.WebConfigModifications.Add(modification);
// Save web.config changes.
webApp.Farm.Services.GetValue().ApplyWebConfigModifications();
// Serialize the web application state and propagate changes across the farm.
webApp.Update();


This code Add safe control entry to the web.config :

SPWebService myService = SPWebService.ContentService;
SPWebConfigModification myModification = new SPWebConfigModification();
myModification.Path = "configuration/SharePoint/SafeControls";
myModification.Name = "SafeControl[@Assembly='MyCustomAssembly'][@Namespace='MyCustomNamespace'][@TypeName='*'][@Safe='True']";
myModification.Sequence = 0;
myModification.Owner = WebConfigModificationFeatureReceiver.OwnerId;
myModification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
myModification.Value = "";
myService.WebConfigModifications.Add(myModification);myService.Update(); myService.ApplyWebConfigModifications();


References :
http://www.crsw.com/mark/Lists/Posts/Post.aspx?ID=32
http://blogs.devhorizon.com/reza/?p=459
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebconfigmodification.aspx



2. Deploying custom XML File in the Sharepoint CONFIG folder ( C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\CONFIG

Steps to perform it:

1. Write an xml file called webconfig.[myname].xml

2. Add yours web.config sections into "actions" node:

<?xml version=”1.0″ encoding=”utf-8″ ?>

<actions>

<add path=”configuration/appSettings”>

<add key=”MyFilePath” value=”C:\temp\path\” />

</add>

<add path=”configuration”>

<connectionStrings />

</add>

<add path=”configuration/connectionStrings”>

<remove name=”MySqlServerConnection” />

<add name=”MySqlServerConnection” connectionString=”server=[server];database=

db];Integrated Security=SSIP;” providerName=”System.Data.SqlClient” />

</add>

</actions>




3. Copy your xml file into C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\CONFIG folder

When you'll create a new web application or extend web application the web.config will be updated with yours sections by merging them into the web.config.

If you want to immediately apply the changes you have to run : stsadm –o copyappbincontent

Reference: http://claytonj.wordpress.com/2008/03/19/custom-webconfig-settings-in-sharepoint/


3. See also : http://blog.thekid.me.uk/archive/2007/03/24/web-config-modification-manager-for-sharepoint.aspx



Sunday, February 22, 2009

Document library internal fields

Recently i was needed to use OpenXml in Moss (hopefully i will write on this soon), one of the issue i needed to handle was the fact that it will only work of office 2007 files and not on pdf/office 2003/txt files and more.

After  a short google seach i found all the relevant suffix (http://msdn.microsoft.com/en-us/library/aa338205.aspx , http://office.microsoft.com/en-us/word/HA100069351033.aspx), so all i needed is the file suffix. However, i was very surprised to find out that non of the SPFile properties or the SPListItem properties contains the document suffix (the last one make sense).

Then i remembered that sharepoint document library (as so list) have hidden/frombase/readonly fields that contains all kind of parameters, like:

BaseName - Document prefix.
FileLeafRef - Prefix.Suffix.
EncodedAbsUrl - Full document url.
DocIcon - Document suffix.
Author - Created by.
Editor - Modified by.
FileDirRef - Directory id and directory name (seperated by  ;#).
ContentTypeId - Content type id.
FileSizeDisplay - File size.
GUID - File guid.

So i used the DocIcon field to get the suffix and to check if the document support OpenXml.

Not enough details in error message

We all have got the famous error message "An unexpected error has occurred", or a message that was to short like "The file is not exist".

In most cases it will be very helpful if we know more details, specially when getting "An unexpected error has occurred" then doesn't help us at all.

So to get more details open the web.config, find the root configuration\SharePoint\SafeMode and change the attribute CallStack from false to true. Then find configuration\system.web\customErrors and change the attribute mode from on to off.

Saturday, February 21, 2009

Operation is not valid due to the current state of the object

It's one of the common errors that we get when we developp with sharepoint object model.

To resolve this error you can check :

1. Application Pool Identity


When you use sharepoint object model from WEB SERVICE , you have to check that the identity of it application pool has the required rights to call the MOSS methods. In particular, the right to open site(SPite site = new SPsite).

2. Disposing of yours Sharepoint Objects

Check that you have correctly disposed yours Sharepoint Objects.
(see
Best Practices: Using Disposable Windows SharePoint Services Objects )

Specifically, if you writed code like this:
using (SPSite site = new SPSite(SPContext.Current.Site))
{
using (SPWeb web = site.OpenWeb(site.OpenWeb()))
{
string ItemID = web.Lists["myListName"].Items[0]["myItemID"].ToString();
}
}


It's preferable to modify this code by:
try
{
SPWeb webContext = null;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(webContext.Site.ID))
{
using (SPWeb web = site.OpenWeb(webContext.ID))
{
string ItemID = web.Lists["myListName"].Items[0]["myItemID"].ToString();
}
}
});
}
catch (Exception ex)
{
}
finally
{
if (webContext != null)
webContext.Dispose();
}

Wednesday, February 18, 2009

How to add an PDF icon to MOSS document libraries

To specify the .gif file that you want to use for the icon that represents PDF documents in yours Document librairies, follows theses steps:

1. Copy the .gif file that you want to use for the icon to the following folder on the server:
Drive:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\60\Template\Images


2. Edit the Docicon.xml file (located on \Program Files\Common Files\Microsoft Shared\Web server extensions\60\Template\Xml or \Program Files\Common Files\Microsoft Shared\Web server extensions\12\Template\Xml ) and add the following line in the < ByExtension > section

< key="pdf" value="MyPicture.gif">
*replace "MyPicture.gif" by the name of your picture

3. IISRESET


Reference : http://support.microsoft.com/kb/837849

Monday, February 16, 2009

CreatePage doesn't work

A strange behaviour we recently bumped into was that the "CreatePage" action redirect a user to the "Access Denide" page eventhough this user is a member of the site contributors.

In order to solve this situation follow these steps:

1. Go to Site Actions -> Site Settings ->Modify all site settings
2. Go to Galleries -> Master pages and page layouts
3. From the list toolbar, select Settings -> Document library settings
4. Select permissions for this document library
5. Add 'Restricted Read' access to the required groups

How to add SharePoint aspx template to a document library?


SharePoint allows us to upload to a document library an aspx and html custom pages and view them as SharePoint page.
However, when we tried to upload a custom page with SharePoint master page (like~/_layouts/application.master) or code it didn't worked, and we got a "Configuration Error" page.

The solution:


1. Add the following to the custom page:

<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls"
Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c" %>

<%@ Register Tagprefix="WebPartPages"
Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint,
Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@
Register Tagprefix="OSRVWC" Namespace="Microsoft.Office.Server.WebControls"
Assembly="Microsoft.Office.Server, Version=12.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c" %>

<%@ Register Tagprefix="SPSWC" Namespace="Microsoft.SharePoint.Portal.WebControls"
Assembly="Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c" %>

<%@ Register Tagprefix="SEARCHWC"
Namespace="Microsoft.Office.Server.Search.WebControls" Assembly="Microsoft.Office.Server.Search,
Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@
Register Tagprefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls"
Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c" %>


2. Then open the web.config and replace the tab <PageParserPath/> with the following path:

<PageParserPath
VirtualPath="/sites/*" IncludeSubFolders="true" CompilationMode="Always"
AllowServerSideScript="true" />


See also : http://www.bluedoglimited.com/SharePointThoughts/ViewPost.aspx?ID=242


Sunday, February 15, 2009

Working with large lists in Office SharePoint Server 2007

Microsoft published a very interresting white paper about working with large lists in moss:
http://technet.microsoft.com/en-us/library/cc262813.aspx
This white paper compare performance of differents methods that are used when working with SPList:
  • SPList with For/Each
  • SPList with SPQuery
  • SPList with DataTable
  • SPListItems with DataTable
  • Lists Web service
The results show that using SPQuery with indexed columns are recommended to improve performance of retriewing datas from large Sharepoint List.

Unauthorized (401.1) Exception when calling Sharepoint Web Services

We get this error when we work with moss farm deployment scenario that implements load balancing.
In fact, it's a security fix in adress resolution mechanism that prevent a machine to resolve the loopback address from accepting a connection unless that machine name matches the NETBIOS name

One solution is to use the server name instead of the load balanced IP.

Another solution is to modify configuration entries on all servers of our farm as described below:
  • Add the DisableLoopbackCheck registry entry discussed in this Microsoft KB article.
    Note: you will need to reboot your server before the DisableLoopbackCheck takes effect.
  • Be sure to add your load balanced host name for your web farm to the Hosts file on each front end web server. Use the loop-back IP address (127.0.0.1).
    This will ensure that each web server looks at itself to access the web services preventing any trips back out to the load-balancer - and possibly calling the web service another web server in the farm.
Mark Wagner posted on his blog an article that describes this issue : http://www.crsw.com/mark/default.aspx

See also Microsoft KB article :http://support.microsoft.com/default.aspx?scid=kb;EN-US;896861

SharePoint Dispose Checker Tool (SPDisposeCheck)

SharePoint Dispose Checker Tool (SPDisposeCheck) is finally available!
You can download it from http://code.msdn.microsoft.com/SPDisposeCheck.

"SPDisposeCheck is a tool to help you to check your assemblies that use the SharePoint API so that you can build better code. It provides assistance in correctly disposing of certain SharePoint objects to help you follow published best practice. This tool may not show all memory leaks in your code. Further investigation is advised if you continue to experience issues." (Paul Andrew)

For resuming, this tool allows moss developpers to check that they correctly use the recommended best practices, in particular:

Best Practices: Using Disposable Windows SharePoint Services Objects
Best Practices: Common Coding Issues When Using the SharePoint Object Model