Community Kit for SharePoint


Few months ago I joined Community Kit for SharePoint team. It’s a collaborative open-source effort to extend and adapt SharePoint for different communities. This project is led by Lawrence Liu, Senior Technical Product Manager and Community Lead at Microsoft (his blog runs on SharePoint). It’s hosted on CodePlex, at http://www.codeplex.com/CKS.

Right now there are different editions in progress:

I’m collaborating in Corporate Intranet and Internet/Extranet edition as a developer. I’ll publish news from this project on a regular basis.

Stay tuned for much more free releases from CKS project very soon. If you would like to contribute, please visit the project page and see where you can help.

How to Optimize SharePoint Designer’s Use of Content Types in a Workflow

I’m annoyed by many little details of the SharePoint Designer Workflow editor, but the main one is that it profligates in the creation of content types. It creates one content type for any custom form that you create when collecting data from a task. Moreover, it doesn’t give you the chance to reuse an existing type….every new task is a new content type in the Tasks list.

However, you CAN reuse existing content type for the Tasks list. You just have to create the first form as usual and then create a second form with a easy-to-find name such as “DUMMY”. Then, a little bit of manual work follows:

  • Open the XOML file of your workflow with right click, choosing “Open With” then “SharePoint Designer (Open As XML)
  • Find the first “CollectDataTask” action, such as this one

    <ns0:CollectDataTask x:Name=”ID15″ ContentTypeId=”0x01080100AC1C1A96057F4B4897ED6C99E92728F500A85399B392A23943B207F10B3F8BB318″ TaskId=”{ActivityBind ROOT,Path=taskAM}” Title=”CAF Approval 1″ InProperties=”{x:Null}” __Context=”{ActivityBind ROOT,Path=__context}” OutProperties=”{x:Null}” AssignedTo=”{ActivityBind ROOT,Path=userAM}” />

  • Copy the line after the x:Name field
  • Find the CollectDataTask with the Title=”DUMMY”
  • Replace the content of the line after the Name field with the first action copied data

That’s it! Now you can safely remove the DUMMY content type from the Task list and Site Content Types list.

SharePoint Hotfix is available

Microsoft released, at least, a quick-and-dirty hotfix that fixes up several issues with SharePoint Services 3.0.

In particular, I’ve found one of the issues to be very annoying. Namely, when you create a site and customize a list view to something other that the default view and then save the site as a template, these changes are not saved. So, when you create another site based on this template, the list view you customized reverts to the default view.

Among other issues, this is solved in the Hotfix that can be found on this address: http://support.microsoft.com/default.aspx?scid=kb;EN-US;934790

Well…now we have to wait for the SP1 to become available…..I hope it will be this year.

COM Again (0x81020037)

I found this “descriptive” error message in a fragment of MOSS 2007 code in a webpart that uploads and tags a document with appropriate metadata:

Microsoft.SharePoint.SPException: DOMAINuser has modified the file Sample.doc
System.Runtime.InteropServices.COMException (0x81020037)

The code 0x81020037 is “Save Conflict” error code in COM. The culprit:

SPListItem doc = list.Add();
doc[“Field1”] = “Value”;
doc[“Field2”] = “Value”;
doc.CheckIn(“Check-in Message”);
doc.Update(); <-- this is the line that throws the error I tried reversing CheckIn and Update methods, with no success. However, the following trick did the job: SPListItem doc = list.Add();
doc[“Field1”] = “Value”;
doc[“Field2”] = “Value”;
doc.CheckIn(“Check-in Message”);
doc = FindByTitle(doc.Title)
doc.Update();

FindByTitle is a custom method I wrote that finds a SPListItem in a SPList, performing a search on the Title field.

The explication: the underlying COM scaffolding doesn’t like the Update() method after CheckIn(). I had to “reacquire” the item and perform the Update() on this new reference to the same document.

Elementary, dear Watson….

Authentication when consuming a web service with Integrated Authentication

The most convenient way is to pass the user credentials from the client to the web service, providing a DefaultCredential object to the Credentials property of the web service proxy:

ws.Credentials = System.Net.CredentialCache.DefaultCredentials;

before invoking the web service.

How to Serialize a Collection

In a fragment of a code I’m working on, I must serialize a collection of links into an XML file. Fortunately, .NET Framework provides a quick XmlSerializer class to do the dirty job for you.

Well, almost…

The problem

If you try to serialize a class derived from CollectionBase, the Serialize method will throw a nasty exception.

The workaround

Use a container class, put the CollectionBase-derived class as a property, decorate this property with XmlArray and XmlArrayItem tags.

[Serializable]

public class CollectionContainer

{

private LinkCollection _links= new ColeccionEnlaces();

[XmlArray(“Links”)]

[XmlArrayItem(“Link”,typeof(Link))]

public LinkCollection Links

{

get

{

return _links;

}

set

{

_links = value;

}

}

}

Data Caching in SharePoint 2003

If you are used to the ASP.NET Cache object, you can use it in SharePoint (after all, it’s just an ASP.NET extended application). However, the Web part framework encapsulates this Cache and enables you to have per-webpart and per-user cache. How? After a little bit of investigation I’ve found it out. The reason was to find out how to remove a cached item outside the webpart.

After inserting a key/value pair using SharePoint’s PartCacheWrite method, SharePoint creates an entry in the Application Cache object (remember that the cache is shared among all the users), with a custom prefix attached to your own key. This prefix includes:

  • SharePoint webpart key:
    • Request URL
    • Creation date and time of the containing WebPartPage
    • Webpart UniqueID
  • User Security Identifier (SID) in hexadecimal format
  • “?” character which marks the end of SharePoint prefix
  • Your own key

 

So, let’s say you’ve cached an object within a webpart named “_ctl6” (default names for no-name webparts) with a key of “abc” and that the webpart is placed under the URL “/C7/Informatica/default.aspx”. The real cache key is:

/C7/Informatica/default.aspx09/27/2006 11:49:49_ctl60x01050000000000051500000069CE0AC3F42CDE9F7071B56E87080000?abc

It can be broken into the key components:

/C7/Informatica/default.aspx09/27/2006 11:49:49_ctl60x01050000000000051500000069CE0AC3F42CDE9F7071B56E87080000?abc

is composed of:

  • /C7/Informatica/default.aspx
    (Request URL)
  • 09/27/2006 11:49:49 (Creation date of the URL page in SharePoint server time)
  • _ctl6
    (UniqueID of the webpart)
  • 0x01050000000000051500000069CE0AC3F42CDE9F7071B56E87080000
    (User SID in hex format)
  • ? (separating character)
  • abc
    (your custom key)

     

It also inserts two dependency strings, used to invalidate per-webpart or per-user cached data. The names of those keys are Depend_String and Depend_String_Per_User, followed by a SharePoint webpart key:

Depend_String_Per_User/C7/Informatica/default.aspx09/27/2006 11:49:49_ctl7

 

 

Shed some light into SharePoint web part errors

Seeing many of those “descriptive” SharePoint errors like this one lately:

Error
The “MyWebPart” Web Part appears to be causing a problem.
Web Parts Maintenance Page: Use this page to temporarily disable Web Parts or remove personal settings.
Troubleshoot issues with Windows SharePoint Services.

If you want to see more meaningful error description, do a simple trick. Change the following line in your SharePoint web.config into something like this:

<SafeMode MaxControls=”50″ CallStack=”true”>

Of course, make sure NOT to change this switch in your production environment, as it could reveal potentially sensitive information.

Active Directory or “How I Learnt to Live With the Ugly COM Guts”

In a project I’m working on, I have to authenticate a user on a custom SharePoint 2003 login form (Yes, that’s possible….more on it will be coming soon). It is a straightforward task, once you overcome the System.DirectoryServices namespace oddities.

In essence, I try to bind a user credentials to a Active Directory LDAP server. If successful, the account is active and with a valid password.

But, what happens when you have a user with “User must change password on the next logon” checkbox turned on? If you try to bind the user, LDAP will throw an error because the credentials you’ve supplied are not valid.

It was an imperative to be able to check for this condition. After a lot of googling, I’ve come out with the solution:

DirectoryEntry user;

System.Int64 largeInt = 0;

IADsLargeInteger int64Val = IADsLargeInteger) user.Properties[“pwdLastSet”].Value;

largeInt = int64Val.HighPart * 0x100000000 + int64Val.LowPart;

if(largeInt == 0)

{

// First login detected

}

Pretty much obfuscated, isn’t it?

It seems that Active Directory stores the “must change password” condition in a property called pwdLastSet, which also stores the date when the password was last set. If this value is zero, the password has not yet been set, ie “must change password” check is marked in the User Properties Tab.

But if you try to check the value directly, you’ll face a lot of exceptions from the underlying COM scaffolding. The pwdLastSet property is a 64-bit integer value which maps into a IADsLargeInteger type (found in “ActiveDs COM Type Library”). This type has two 32-bit halves: HighPart and LowPart. So, if you want to translate this into a large integer (System.Int64 in .NET Framework) you have to perform the multiplication shown in the code above.

A lot of headache could have been avoided if this strange quirk had been well-documented.

Ruby on Rails, the next tidal wave?

I’ve been looking for information about the new buzzword in town: Ruby on Rails (aka RoR). I thought it was just another web development framework, like Struts for instance.

I was wrong.

First of all, Ruby on Rails are two related technologies stitched together, namely Ruby and Rails.

Ruby is a fully-fledged object-oriented language. It has some of the elegance of Python, some of the power of Smalltalk and some spartainty of SML. It was developed in Japan in 1994, and in the last years it began to spread around the world. Ruby seems to follow natural (at least in English) order of words, so the code in Ruby is easy to follow, as much as I could see.

Check for yourself:

"gin joint".length
"Rick".index("c")
-1942.abs
sam.play(aSong)

Rails is a database-backed web framework built with Ruby. It has full object-relational mapping support, AJAX handlers, auto-generated code and it implements a Model-View-Controller (MVC) paradigm. It relies heavily on reflection and metaprogramming.

So, what’s the sum of those two pieces of technology? Ruby on Rails, claimed to be “the most productive web development framework so far“.

Is it so? I am a born skeptic, so I paid more careful visit to the tutorials and other documentation available on the RoR site.

I’m still perusing it, but I’m impressed. RoR allows you to use scaffolding, or code generated by default, to have a working CRUD application while you build your own features. Then, you just remove the scaffolding, much like when building a house.

The productivity of RoR is what shocked me: the flagship application of Rails, Basecamp, is a full project collaboration portal (SharePoint Light, I’d say). It was build by a single developer in two months and contains a mere 4.000 lines of code.