Archive

Archive for January, 2009

Email Regular Expression Validation

January 28th, 2009 Dominick Cosgrove No comments

If  you need to validate a email address either through Javascript, server side code or asp.net regular expression validator then the best expression I have found is by Mykola Dobrochynskyy on Code Project.

^(([\w-]+\.)+[\w-]+|([a-zA-Z]{1}|[\w-]{2,}))@” + @”((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]? [0-9]{1,2}|25[0-5]|2[0-4][0-9])\.” + @”([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]? [0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|” + @”([a-zA-Z]+[\w-]+\.)+[a-zA-Z]{2,4})$

An example using this would be:

string regEx = @”^(([\w-]+\.)+[\w-]+|([a-zA-Z]{1}|[\w-]{2,}))@” + @”((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]? [0-9]{1,2}|25[0-5]|2[0-4][0-9])\.” + @”([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]? [0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|” + @”([a-zA-Z]+[\w-]+\.)+[a-zA-Z]{2,4})$”;

foreach (string recipient in recipients)
{
if(!Regex.IsMatch(recipient.Trim(), regEx))
{
throw new Exception();
}
}

Reference: http://www.codeproject.com/KB/recipes/EmailRegexValidator.aspx?display=Print

Categories: Uncategorized Tags:

SharePoint ServerTemplate ID’s

January 26th, 2009 Dominick Cosgrove No comments

This is a quick reference for all the SharePoint Server Template IDs.

100 Generic list   101 Document library
102 Survey   103 Links list
104 Announcements list   105 Contacts list
106 Events list   107 Tasks list
108 Discussion board   109 Picture library
110 Data sources   111 Site template gallery
112 User Information list   113 Web Part gallery
114 List template gallery   115 XML Form library
116 Master pages gallery   117 No-Code Workflows
118 Custom Workflow Process   119 Wiki Page library
120 Custom grid for a list   130 Data Connection library
140 Workflow History   150 Gantt Tasks list
200 Meeting Series list   201 Meeting Agenda list
202 Meeting Attendees list   204 Meeting Decisions list
207 Meeting Objectives list   210 Meeting text box
211 Meeting Things To Bring list   212 Meeting Workspace Pages list
300 Portal Sites list   301 Blog Posts list
302 Blog Comments list   303 Blog Categories list
850 Page Library   1100 Issue tracking
1200 Administrator tasks list   2002 Personal document library
2003 Private document library      

You can get the List Templates using SPWeb.ListTemplates

References:

http://msdn.microsoft.com/en-us/library/ms415091.aspx

Setting the value of a BDC field Programmatically

January 21st, 2009 Dominick Cosgrove No comments

You cannot set the value of a BDC (Business Data Catalog) field in the same way that you set standard fields in SharePoint e.g:

SPListItem item = myList.Items.Add();
item["Title"] = "Product Information";

Instead you must use the EncodeEntityInstanceId method of the EntityInstanceIdEncoder class of the  Microsoft.Office.Server.ApplicationRegistry.Infrastructure class library. First you can detect if your field is a BDC field by:

if(item.Fields["MyField"].TypeAsString == "BusinessData")

You then need to:

//Get a reference to the field
SPField myField = spItem.Fields["EmployeeID];

//Get the entity Name for the field
XmlDocument xmlData = new XmlDocument();
xmlData.LoadXml(myField.SchemaXml);
String entityName = xmlData.FirstChild.Attributes["RelatedFieldWssStaticName"].Value;

//Set the Entity Instance value
spItem[entityName] = EntityInstanceIdEncoder.EncodeEntityInstanceId(new object[] { "123456" });

//Set the field display value
spItem["EmployeeID"] = "123456;
1 comments  Saturday, January 24, 2009

Connected WebParts – No Filtered Parameters

Posted by Dominick Cosgrove at 9:05 PM Labels: ,

OK this may be obvious but it caught me out and god knows it caused me to tear my hair out for a while.

I was creating a custom consumer WebPart that I wanted to connect to a URL and BDC Filter WebParts. There are loads of examples out there of how to do this. Basically Windows SharePoint Services makes use of the connection framework and provides additional interfaces called IFilterValues and IItransformableFilterValues to make it easy to create Web Part connections for filtering scenarios.

The issue I had was once I implement the code as per the various examples on the web, there were no filter parameters available to when you configure the connection.

image

The problem lies with the ConsumerParameterCapabilities Enumeration, which is used by a consumer Web part to indicate supported filter parameter capabilities. The samples on the web all seem to use:

ConsumerParameterCapabilities.SupportsMultipleValues

and

ConsumerParameterCapabilities.SupportsAllValue

Unfortunately this did not seem sufficient for the BDC and URL filter WebParts, after some trail and error I established that the minimum required is:

ConsumerParameterCapabilities.SupportsAllValue

or

ConsumerParameterCapabilities.SupportsEmptyValue

How ever it does work if you specify all ConsumerParameterCapabilites. The ConsumerParameter method allows you to have or statements so you can effectively set the parameters like this:

parameters.Add(new ConsumerParameter(
                    "Personnel Number",
                    ConsumerParameterCapabilities.SupportsAllValue
                    |
                    ConsumerParameterCapabilities.SupportsEmptyValue
                    )

or

parameters.Add(new ConsumerParameter(
                    "Personnel Number",
                    ConsumerParameterCapabilities.SupportsAllValue
                    |
                    ConsumerParameterCapabilities.SupportsEmptyValue
                    |
                    ConsumerParameterCapabilities.SupportsMultipleValues
                    |
                    ConsumerParameterCapabilities.SupportsSingleValue
                    )
                );

So to summaries, make sure you are using the correct ConsumerParameterCapabilities for your provider webpart or else you will not see the parameters you are expecting to see.

References

Writing a Simple Filter Consumer Web Part Sample

MOSS 2007 Filter webparts part 1 – create your own provider and consumer

Query Child Content Types in your CAML Query

January 15th, 2009 Dominick Cosgrove No comments

The Content Query Web Part that ships with MOSS and is enabled with the Publishing Feature has an option to include the child content types of that content type in filtering the data. I wanted to replicate this functionality in my own WebPart that utilized the SPSiteDataQuery to query the site. The SPSiteDataQuery accepts a CAML query to filter the results.

image

It is easy enough to query for all documents in a site that are of content type x:

<Where>
  <Eq>
    <FieldRef Name=’ContentType’/>
    <Value Type=’Text’>HR Document</Value>
  </Eq>
</Where>

But what happens if you want to query all children of content type x. In this example if you had CV, Application Form e.t.c. which all inherited from HR Document how do you build your query. You can add each additional Content Type into the WHERE clause of the CAML query, but this is an convoluted approach as any time you add a new child content type you’ll have to modify your CAML query.

The answer lies with how the ContentTypeID is constructed in SharePoint. The ContentTypeID is a concatenation of parent child ContentTypeIDs, this is to say that a ContentTypeID is composed of its parent ContentTypeID post fixed with a  it’s own identifier.

Content Type Parent Content Type Content Type ID
System   0x
Item System 0×01
Document Item 0×0101
HR Document Document 0x0101002C3431777FFD0742A58D02ABC9C5FA62
CV HR Document 0x0101002C3431777FFD0742A58D02ABC9C5FA6201
Application Form HR Document 0x0101002C3431777FFD0742A58D02ABC9C5FA6202

Knowing this you can construct a CAML query that uses the <BeginsWith> select statement.

To return all Documents you can use the following query:

<Where>
   <BeginsWith>
     <FieldRef Name=’ContentTypeId’/>
     <Value Type=’Text’>0×0101</Value>
   </BeginsWith>
</Where>

To return all HR Documents you can use the following query:

<Where>
   <BeginsWith>
     <FieldRef Name=’ContentTypeId’/>
     <Value Type=’Text’>0x0101002C3431777FFD0742A58D02ABC9C5FA62</Value>
   </BeginsWith>
</Where>

You can find the ContentTypeID by going to Site Actions | Site Settings | Site Content Types, and select the parent content type you are interested in. In the URL you will see the ContentTypeID in the page URL. For example:

image

RunWithElevatedPrivileges Gotcha

January 14th, 2009 Dominick Cosgrove 1 comment

The Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges is a useful method that can execute a delegate method that runs a subset of code in the context of an account with higher privileges than the current user.

Sample usage:

SPSecurity.RunWithElevatedPrivileges(delegate(){    // implementation details omitted});
 
Something you need to watch for, which is eluded to in the SDK is that you must create a new SPSite object inside the delegate because SPSite objects created outside do not have Full Control even when referenced inside the delegate. Now it’s not only the SPSite object that you need to concern yourself about. For instance if you have some custom code that run with Elevated Privileges and that code accepts a SPListItem as a parameter, then that SPListItem will have the same security as when it was created. This is to say that the RunWithElevatedPrivileges method does not increase the security for objects that already exist. You need to create the objects within the method for them to adopt the elevated privilege.
 
Take for example the following scenario; You have two folders in the same document libraries, one (Folder A) where users have the permissions to contribute with the other (Folder B) is locked down and only the system administrator can contribute, all other users only have read access. The use case is that, when a user sets the document approval status to approved and checks in the file the file will be moved from Folder A to Folder B. The issue arise where the user who executes the method does not have the correct privileges on Folder B to add the file. This is where RunWithElevatedPrivileges comes into play. The following shows an example a possible Move Document method:
 
This code will Error!
 
private void MoveDocument(SPItemEventProperties properties)
        {
            string targetDir = [PathToSharePointFolder];

            SPList list = web.Lists[properties.ListId];
            SPListItem item = list.GetItemById(properties.ListItemId);
            SPFile file = item.File;

            try
            {
                SPSecurity.RunWithElevatedPrivileges(delegate()
                       {
                           using (SPSite site = new SPSite(properties.SiteId))
                           {
                               using (SPWeb web = site.OpenWeb(properties.RelativeWebUrl))
                               {
                                   file.MoveTo(targetDir + "/" + file.Name, true);
                               }
                           }

                       });

            }
            catch (Exception ex)
            {
            }
        }

 
When you run this code in your ItemCheckedIn EventHandler you notice that you’re getting an unauthorised exception! What is causing this?
 
Well the culprit in this case is the SPFile object. As the file object is instantiated out side of the RunWithElevatedPrivileges method the file object has the security context of the user who performed the action. This user does not have sufficient privileges on folder B hence the error message.
 
To rectify the issue you can instantiate the file object within the RunWithElevatedPrivileges method as show below:  
 
This code should execute successfully
 
private void MoveDocument(SPItemEventProperties properties)
        {
            string targetDir = [PathToSharePointFolder];

            try
            {
                SPSecurity.RunWithElevatedPrivileges(delegate()
                       {

               SPList list = web.Lists[properties.ListId];
                          SPListItem item = list.GetItemById(properties.ListItemId);
                         SPFile file = item.File;

                           using (SPSite site = new SPSite(properties.SiteId))
                           {
                               using (SPWeb web = site.OpenWeb(properties.RelativeWebUrl))
                               {
                                   file.MoveTo(targetDir + "/" + file.Name, true);
                               }
                           }

                       });

            }
            catch (Exception ex)
            {
            }
        }

 
So it is important to be aware of where SharePoint Object are created when using the RunWithElevatedPrivileges method and if you are experiencing a unauthorised error the chances are that a object is being created outside of the RunWithElevatedPrivileges method.
 
Note: The code in this article is for demonstration purposes and should not be used in any other context than what it is intended for.

ProcessBatchData To Delete Files from a Document Library

January 14th, 2009 Dominick Cosgrove No comments

This evening I had to clear down some test data from a large document library. As performance of the delete function degrades on extremely large document libraries (see Software Boundary Document) using an iterative delete function was very slow. In the past I’ve used the SharePoint List web service (http://_vti_bin/lists.asmx) to batch delete files, but I wondered if there was a way to improve performance of the delete through API.

During my investigation I came across an article by The Kid which shows you how to delete large numbers of list items using the ProcessBatchData. I implemented the same code, but the files were not being deleted. Further investigation led me to a great article by SteveC titled SPWeb.ProcessBatchData. A list is a list is a list? Here Steve explains how to delete documents using the ProcessBatchData method and the owsfileref property. The owsfileref is a little known property that takes the ServerRelativeUrl of the file.

Here is the code for my console app that deletes the files in a Batch Method approach. I found it to be extremely quick way of deleting large number of documents from a library.

Hope this helps you it certainly helped me! Saved me loads of time hence why I’m writing as I’m sure I’ll be using it again and again :)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;

namespace DeleteItemsFromDocumentLibrary
{
    class Program
    {
        static void Main(string[] args)
        {
            string SiteUrl = args[0];
            string ListName = args[1];
            int NumberOfFilesToDelete = Convert.ToInt32(args[2]);

            using (SPSite site = new SPSite(SiteUrl))
            {

                using (SPWeb web = site.OpenWeb())
                {
                    SPList CurrentList = web.Lists[ListName];
                    StringBuilder sbDelete = new StringBuilder();
                    sbDelete.Append(“<?xml version=\”1.0\” encoding=\”UTF-8\”?><Batch>”);

                    int i = 0;
                    foreach (SPListItem item in CurrentList.Items)
                    {
                        SPFile file = item.File;
                        if (i >= NumberOfFilesToDelete)
                            break;
                        sbDelete.Append(“<Method>”);
                        sbDelete.Append(“<SetList Scope=\”Request\”>” + CurrentList.ID + “</SetList>”);
                        sbDelete.Append(“<SetVar Name=\”ID\”>” + Convert.ToString(item.ID) + “</SetVar>”);
                        sbDelete.Append(“<SetVar Name=\”owsfileref\”>” + file.ServerRelativeUrl + “</SetVar>”);
                        sbDelete.Append(“<SetVar Name=\”Cmd\”>Delete</SetVar>”);
                        sbDelete.Append(“</Method>”);
                        i++;
                    }

                    sbDelete.Append(“</Batch>”);

                    try
                    {
                       web.ProcessBatchData(sbDelete.ToString());
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(“Delete failed: ” + ex.Message);
                        throw;
                    }

                    Console.WriteLine(“Deleted {0} files successfully”, NumberOfFilesToDelete);
                    Console.ReadLine();
                }
            }
        }
    }
}

View Raw XML from SharePoint Search Results

January 11th, 2009 Dominick Cosgrove No comments

It is often useful to view the Raw XML of the SharePoint Search Results. This is easily achieved by modifying the XSLT that is used to render the results. The following details the steps:

Navigate to the Advanced Search Page;
Perform a search to return some search results;
Edit the page (Site Settings | Edit Page);
Edit the Search Core Results WebPart (Edit | Modify Shared WebPart);
Under the Data View Properties click the XSL Editor button;
Select all the XSL and save it somewhere to back up the default XSL;
Clear the content of the editor and enter the following XSL:

<xsl:copy-of select="*"/>

Save the changes;

Apply the changes to the Web Part and Click OK;

You will now see that the format of the results has changed. View the source of the page to reveal the raw XML.

This is nothing new, but is very used full to get the Raw XML so you can then open your favorite XSLT editor and generate some nice formatting for your search results.

File Not Found SharePoint Error

January 3rd, 2009 Dominick Cosgrove 1 comment

If in SharePoint 2007 (WSS or MOSS) you get a file not found error on a page, the chances are you are missing a custom or 3rd Party UserControl.

image

A easy way to determine what control is missing is to:

1. Enable debugging – see my previous post (link);

image

2. View the source of the error page. In Internet Explorer, right click on the error page and select view source. In the source you will find the inner exception, which will give the path to the missing ascx UserControl file;

<!-- [FileNotFoundException]: The file /_controltemplates/Centrix/HRQuickFileSearch.ascx does not exist.   at Microsoft.SharePoint.ApplicationRuntime.SPRequestModuleData.GetWebPartPageData(HttpContext context, String path, Boolean throwIfFileNotFound)   at Microsoft.SharePoint.ApplicationRuntime.SPVirtualFile.CalculateFileDependencies(HttpContext context, SPRequestModuleData basicRequestData, ICollection& directDependencies, ICollection& childDependencies)   at Microsoft.SharePoint.ApplicationRuntime.SPDatabaseFile.EnsureDependencies(HttpContext context, SPRequestModuleData requestData)   at ….-->