RegEx Tuesday Challange

An interesting site to practice your regular expression skillls

Week 1 – Marking repeating words – /\b([\w']+)\s+(\1)\b/gi
Week 2 – CSS colors – /#[\da-h]|rgb\( ?([\d.%]+), ?([\d.%]+), ?([\d.%]+) ?\)|rgba\( ?([\d.%]+), ?([\d.%]+), ?([\d.%]+), ?([\d.%]+) ?\)/ -not complete solution
Week 3 – Dates and time – /^(1\d{3}|200\d|201[0-2])/(0[1-9]|1[012])/(0[1-9]|[12][0-9]|3[01]) ([0-1]\d|2[0-3]):[0-5]\d(:[0-5]\d)?$/
Week 4 – Italic markup – /\*{1}([^*]+)\*(?!\*)/g -not complete solution
Week 5 – Numbers – /^([0-9]{1,3}|[0-9]{1,3}([, ]{1}\d{3})+)([.,][\d]+)?$/

Encoding paths for document libraries

If you try to create a folder or a document in a document library with a name containing one of these characters ( \ / : * ? “” | # { } % ~ &), you will get an error saying something about invalid characters. If you still want to create the folder or document, even if it’s name should contain one of the above mentioned characters, I recommend the following two extension methods:

public static class Extensions
{
public static string EncodePath(this string path)
{
return SPHttpUtility.UrlKeyValueEncode(path).Replace("%", "_0x24_");
}
public static string DecodePath(this string encodedPath)
{
return SPHttpUtility.UrlKeyValueDecode(encodedPath.Replace("_0x24_", "%"));
}
}

The first method will return a string which doesn’t contain any forbidden characters, so Sharepoint won’t complain anymore when creating the folder or the document. But this method also makes sure that if needed, the encoded name can be decoded, and the original name, with the forbidden characters, can be displayed, if using the second method.
The two methods are reusing standard Sharepoint encoding/decoding methods. Unfortunately, the UrlKeyValueEncode method is not enough for the job, because it uses the “%” as an escape character, which is forbidden in our case. So I  replaced this character which its hexadecimal ASCII code, the resulting string being fully compatible with the folder names Sharepoint expects, when creating a folder or file in a document library.

Saving site properties

Maybe you were, just like me, a little confused about the SPWeb.AllProperties and SPWeb.Properties. What exactly is the difference between the two? When to use which?

Today I think I have an answer to these questions.

SPWeb.Properties is an older version of SPWeb.AllProperties and it has been kept in Sharepoint 2010 for backward compatibility. SPWeb.Properties supports only string values, because it is a StringDictionary, as opposed to the AllProperties property, which is a HashTable.

So that’s the main difference between the two. Now, when to use which? Never, either of them. :)
Today I have discovered that SPWeb has four methods exactly for handling properties:

SPWeb.GetProperty(Object key)
SPWeb.AddProperty(Object key, Object value)
SPWeb.SetProperty(Object key, Object value)
SPWeb.DeleteProperty(Object key)

Of course, we have to call SPWeb.Update in the end.

Here is the source.

Publishing and content type inheritance

Please read this document first.

You can see, that there are two ways to determine parent-child relationship between content types. You can of course use always the ParentCT+00+GUID way, like I did, but then you will surely bang your head against a wall when it comes to work with publishing.

Scenario:
I created a content type schema for a publishing site, where A was parent for AB, which was parent for ABC, etc. For every content type, I used the ParentCT+00+GUID inheritance schema, which gave me a pretty long content type id for ABC, but what the heck, Sharepoint will handle it, won’t it?
Then I created Page Layouts and associated them with the appropriate content type. I deployed it, I created page instances from the different page layouts. Everything worked just fine. Me happy :)
Then I noticed that even I had one page instance from each page layout (A, AB and ABC), the content type of all three page instances was ABC. I wasn’t so happy anymore, because I built a user control which was using filtering based on the content type of the page instance, so I needed this working correctly.
I did another experiment, and I noticed, that if I add the content type manually to the document library (Settings->Add existing content type from site) then it works correctly: page instance of A will have content type A, page instance of AB will have content type AB and so on.
So I had no other choice, but debug Sharepoint. With the help of the 30 days trial version of Reflector VS PRO, I found the exact flow which takes place when you create a document based on a page layout. At on moment it searches for the BestMatch of a content type id in a content types collection. That code looks like this:
public static SPContentTypeId BestMatch(SPContentTypeId contentTypeId, IEnumerable contentTypeIdCollection)
{
SPContentTypeId result = SPContentTypeId.Root;
int num = 0;
foreach (SPContentTypeId sPContentTypeId in contentTypeIdCollection)
{
int num2 = sPContentTypeId.CountCommonBytes(contentTypeId);
if (num2 > num)
{
result = sPContentTypeId;
num = num2;
}
else
{
if (num2 == num && sPContentTypeId.Length < result.Length)
{
result = sPContentTypeId;
}
}
}
return result;
}

I can’t say I understood what’s happening there, so I tried a different approach. :)
There was another publishing project, created by another team, which was working just fine, though it was also using content type inheritance. I took a look at the content type definitions from that project and it struck me immediately: these content type ids are much SHORTER!

Conclusion:
Pay attention to that link I mentioned above. Create a content type id using the ParentCT+00+GUID only when the parent is a “foreign” content type, meaning it’s either Sharepoint’s or a third party. After you created the first leaf of your content type inheritance tree that way, you can (and should!) continue using the other option: ParentCT+[01..FF] I have rewritten all my content type ids this way, and BANG: the page instance was created with the correct content type!

Great script for Deployment

I have been searching for a couple of days now, for a good script, which can be used on solutions deployment/upgrade, to make the batch wait until the solution is actually deployed.
Finally I found the following script here.


$JobName = "*solution-deployment*something.wsp*"
$job = Get-SPTimerJob | ?{ $_.Name -like $JobName }
if ($job -eq $null)
{
Write-Host 'Timer job not found'
}
else
{
$JobFullName = $job.Name
Write-Host -NoNewLine "Waiting to finish job $JobFullName"

while ((Get-SPTimerJob $JobFullName) -ne $null)
{
Write-Host -NoNewLine .
Start-Sleep -Seconds 2
}
Write-Host “Finished waiting for job..”
}