Site Template - Category

Many times site templates are a good solution to store out-of-the-box customisations. These templates can be retrieved under the 'Custom' tab during the site creation process.

You can however create your own custom tabs, be it with a little workaround: after some searching I found out that the site definition on which the site template is based, apparantly defines the name of tab! Here is how you do it...

1. Create a custom site definition to define the category. You can for example copy the Publishing template.

2. In the webtemp file of you site definition provide the FilterCategories parameter on the Configuration tag. Assign it the string you want to appear on the tab:

< Template Name="CUSTOMSITE" ID="1001" >
< Configuration ID="0" Title="Custom Web Site" Hidden="FALSE"
ImageUrl="/_layouts/images/stsprev.png" Description="Customized site definition for My Team Site"
DisplayCategory="My Site Definitions" FilterCategories="My Custom Site Templates" >
< /Configuration >
< /Template >

3. Install your custom site definition

4. Create a site based on you site definition and customize it.

5. Save your site as template

Your site template will be available on the site creation page under the tab 'My custom site templates'.

A site template is in fact a cab-file with a manifest.xml file in it. In this xml file the site definition ID is stored. Based on this ID the FilterCategories parameter of the site definition is retrieved.

Lookup Fields

Another post on relational data in SharePoint.

The lookup field turns out to be one hell of a powerfull tool! Suppose you want to relate two different list items or documents. For this purpose you need to use the lookup field.
This field internally stores the ID of the related item, but in the drop-down it displays whatever field you want. However, in your CAML queries you can use both values!

To query the display-value, your CAML would look like this:
<Query>
   <Where>
     <Contains>
       <FieldRef Name="Event" />
         <Value Type="Lookup">Cronos</Value>
     </Contains>
   </Where>
</Query>


To perform a query on the ID you just need to specify LookupId='true' in the FieldRef tag:

<Query>
   <Where>
     <Eq>
       <FieldRef Name="Event" LookupId="true"/>
         <Value Type="Lookup">7</Value>
     </Eq>
   </Where>
</Query>

Relational Data in SharePoint

Recently I needed to develop a simple subscription system in a WSS 3.0 environment. My client wanted to have a simple event list on which employees could register (with approval).

One of the fantastic 40 application templates addresses this topic, but as I started thinking about it...I wanted to try to make use of the new possibilities of wss 3.0 concerning multiple content types in a custom list. As it turns out my efforts took me quite far!

Let's start by briefly listing the functional requirements:

  1. There needs to be a table/list to store all events. Several different event types exist: internal or external, workshop or course.
  2. Users can register for internal events, an approval workflow is needed.
The obvious choice would be to use a lookup field on the subscription list to link the 2 lists. However, this would mean we have to write some eventhandlers on the first list to ensure that when an event is deleted, the related subscriptions also get deleted. Why not try to reduce the coding by using a different approach.

Since wss 3.0 it is possible to use multiple content types on one list. So all event types can be joined into one list. To ensure that no event handlers need to be written, we'll need to combine the registration and the event list into one custom list. Again this poses no problem: folders can be used to define a relation between an event and a registration.

So the final idea would be to create some content types for the events that inherit from the folder content type. The registrations for each event are stored in a different content type inside the folder of the event.

We end up with a flexible system! As a event gets deleted, all registrations within the folder are deleted. And no coding needed!

Now we only need to define some views, an approval workflow, use some customized CQWP's to ensure a nice layout and we're all set!

Debugging in SharePoint Land

Debugging in SharePoint might seem at first a little bit harder to do, but this excellent post shows that you still have a lot of day-saving tools at hand!

CS1010: Newline in Constant

Yesterday I bumped into a strange flaw in the IIS compilation logic: The error appeared on a ASP.NET page where I needed to include a string with some script-tags. Apparently the compiler mistook the script-tags in the string for the script tags in the ASP.NET page where I was writing the code. Thanks to the this blog, I figured out that misleading the compiler would do the trick: string strAll = "<SCRIPT lanquage='JScript'>window.alert('" + strValue + "');<"+"/SCRIPT>";

Accessing InfoPath File Attachments in code

Welcome to my first SharePoint-blog! I can't image life as a programmer without the millions and millions of interesting posts on the internet that helped me reach my goals time after time. Since this helped me a lot, time has come to do my part of the share...hopefully I can provide you with some interesting posts as I learn more about SharePoint! Here we go!

The latest project I have been working on required some InfoPath forms processing: once a form was stored in a SharePoint library an EventReceiver needed to process the XML and send an e-mail with a summary of the InfoPath fields. Nothing special, I hear you think...indeed nothing special if it wasn't for the file attachments in the form. Somehow these needed to be converted from a meaningless string back to a file.

If you take a look at the XML that InfoPath produces for the XML file, you'll notice the tag contains one big base64 encoded string. But decoding the string is not enough to extract the file: upon attaching a file InfoPath builds a header which has the following structure:

SizeContents
0: 4 bytes [DECIMAL]199, 73, 70, 65
4: DWORD (4 bytes)Size of the header
8: DWORD (4 bytes)InfoPath Version
12: DWORD (4 bytes)Reserved
16: DWORD (4 bytes)File Size
20: DWORD (4 bytes)Size of FileName buffer
24: VariableName of the file

The first four bytes are not chosen randomly: the first byte is an unexistent ASCII code. Just to make sure the XML field is not misinterpreted as a text field. The other 3 bytes identify the field as an Infopath Form Attachment (73: I, 70: F, 65: A)

So in order to attach the file to a e-mail I need to read out the filename size, the filename and of course the file. Some code:

// file = the deserialized version of the InfoPath Form // objAttachmentResponse = the attachment field byte[] xmlFileString = file.objAttachmentResponse; if (xmlFileString != null) { //length of filename is on place 20 in the byte[], encoded in unicode --> x2 int nameBufferLen = xmlFileString[20] * 2; byte[] fileNameBuffer = new byte[nameBufferLen]; //Name of the file is on place 24 in the byte[] for (int j = 0; j < nameBufferLen; j++) { fileNameBuffer[j] = xmlFileString[24 + j]; } //decode the filename char[] asciiChars = UnicodeEncoding.Unicode.GetChars(filenameBuffer); string fileName = new string(asciiChars); //Remove the trailing \0 character fileName = fileName.Substring(0, fileName.Length - 1); //file content can be retreived after the fileName in the byte[] byte[] fileContent = new byte[xmlFileString.Length - (24 + nameBufferLen)]; for (int j = 0; j < fileContent.Length; j++) { fileContent[j] = xmlFileString[24 + nameBufferLen + j]; } //attach the file to the mail MemoryStream ms = new MemoryStream(fileContent); mail.Attachments.Add(new Attachment(ms, filename)); }