MOSSPH – C# Protocol Handler (with bug fixes)

I have recently had a need to index some custom content sources within MOSS and have been using the MOSSPH protocol handler which can be found on CodePlex (http://www.codeplex.com/MOSSPH) to help me achieve this.

The downloadable solution has everything you need to get started with lots of comments to assist you in implementing custom functionality.  There is however one or two small bugs relating to the retrieval of security descriptors which is necessary when implementing security trimming at query time.  Fortunately I was able to locate these bugs relatively quickly thanks to a very handy blog post from Michaël Hompus which saved me some valuable time.

http://blog.hompus.nl/2009/07/moss-2007—c-protocol-handler-errors-fixed.html

The MOSSPH project is extremely useful to get up and running as quickly as possible when there is a requirement to crawl custom content sources from within MOSS.

Adding an assembly to the GAC on a build event

I don’t know about you, but I keep forgetting the correct syntax/path required for GACing an assembly in a Visual Studio post-build event:

 

“C:\Program Files (x86)\Microsoft Visual Studio 8\SDK\v2.0\Bin\GacUtil.exe” /i $(TargetFileName)

Best way to find where content type is in use

I just happened across a handy class within the SharePoint object model which allows finding where a content type is currently in use within a site much quicker than using the custom code I had previously been using.  This would be handy when unable to delete a content type because it is in use, or if we simply want to know if a content type is in use somewhere within our SharePoint site.

SPContentTypeUsage
Used to track available content types used throughout a site collection.

Info:
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spcontenttypeusage.aspx

Continue reading ‘Best way to find where content type is in use’

SharePoint Memory Leak

I was recently struggling with a memory leak somewhere in my code.  My code which was running in the _LAYOUTS directory was handling content types across sites/lists in a SharePoint configuration. 

On my local machine with a small number of lists/sites everything appeared to be fine, but when running on a test server I could see the memory in use on the server to jump up by several MB every couple of seconds.  After a few minutes the memory on the server could be up to a over a GB.  Eventually an OutOfMemory exception would be thrown.

I pulled all my code apart and ran some profiling tools to find the problem and it turned out to be an SPWeb which was being created and not being closed (unbeknown to me).  So it was an easy solution once found.

I found this MSDN link very useful while looking into this and thought it would be worth highlighting for any developers working with SharePoint:

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

The security validation for this page is invalid

While spending some time working with content types recently I have encountered the following error more times than I care to mention:

The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again.

This error has plagued me throughout my content type endeavours and continued to be displayed intermittently despite having searched the web and attempted the numerous approaches suggested (i.e. SPSecurity.RunWithElevatedPrivileges(), .AllowUnsafeUpdates = true & .FormDigestSettings.Enabled = false).

Having spent time looking deeper into this it appears that there was one technique I had failed to try and wouldn’t you just know it, this one (has so far) appeared to solve all my security problems. 

If you are reading this then you are no doubt aware that for security reasons SharePoint protects the database by preventing a web application from updating unless it has passed security validation.  All of the approaches mentioned above go some way towards this but the best way to update site data is to add a page directive and FormDigest control directly to the aspx form. 

This can be done as follows:

Add page directive to top of aspx page:

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

Add FormDigest control within form tags:

<form id=”Form1″ method=”post” runat=”server”>
   
<SharePoint:FormDigest ID=”spFormDigestControl” runat=”server”/>

    … PAGE CONTENT HERE…
</form>
 

With the above in place I was able to dispense with the .RunWithElevatedPrivileges anonymous method I had wrapped around my update code (in fact I had to or it continued to throw the same error error!).

This has certainly done the trick for me, but it took a little bit of trial and error before I managed to find it. 

Useful link:
http://msdn.microsoft.com/en-us/library/ms472879.aspx

Update Content Type including children

Recently I have been doing some work with Content Types via the SharePoint object model and as well as the read only issue which I have also posted about I ran into a security issue.  Whenever attempting to update a content type and propagate all children I would receive the following error:

“The security validation for this page is invalid”

This one took quite a while for me to get to the bottom of and as it turned out all that was required to fix it was disabling security validation by setting the .FormDigestSettings property before the content type update statement as discussed here.

Having read the above I proceeded to

modify my code as follows:
SPSecurity.RunWithElevatedPrivileges(delegate()
{

    using (SPSite site = new SPSite(strSite))
    {
       
site.AllowUnsafeUpdates = true;
       
using (SPWeb web = site.OpenWeb())
       
{
            
// update will fail unless security validation is disabled
            SPWebApplication webApp = web.Site.WebApplication;
            webApp.FormDigestSettings.Enabled = false;
           
 web.AllowUnsafeUpdates = true;            // code goes here
           
            // update including children
           
contentType.Update(true
);

            web.AllowUnsafeUpdates = false;
            // re-enable security validation
            webApp.FormDigestSettings.Enabled = true;
        }
        site.AllowUnsafeUpdates =
false;
    }
});

By disabling the .FormDigestSettings prior to the update combined with allowing unsafe updates I was able to propagate content type changes to children without receiving any errors.  Hooray!

Updating Content Types

I was having a problem recently where I was unable to issue an update command on a content type without running into the following error:

“The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again.”

After much head scratching, web browsing and trial and error I discovered that when retrieving my content type collection I was inadvertently getting a read only collection.  This was not particularly clear from the documentation, but there in fact two methods available for retrieving a collection of content types and these are web.AvailableContentTypes and web.ContentTypes.  The key difference is that web.AvailableContentTypes is a read only collection and therefore fails when an update is issued.

I amended my code to use web.ContentTypes as follows and it worked as expected:

// get content type using writeable content type collection
SPContentType
contentType = web.ContentTypes["CONTENT_TYPE_NAME"];

// get field to remove from content type
SPField
field = web.Fields["FIELD_NAME"];
SPFieldLink fieldLink = new SPFieldLink(field);

// delete field from content type by field id
contentType.FieldLinks.Delete(fieldLink .Id);

// update
contentType.Update(); 

These links helped me to diagnose this issue: 

Updating a Column Across All Items Within a List

So while working on a custom WebPart I recently needed to update a custom status field across all items within a list , this was a first for me so I explored the various options. 

The obvious approach is to just iterate the list updating each item individually and this could just be done as follows: 

 

using(SPSite site= new SPSite(“SHAREPOINT_URL”))
{
   
using(SPWeb web= site.OpenWeb())
    {
       
// get list
        SPList myList = web.Lists["LIST_NAME"];
       
SPListItemCollection

        ItemCollection = myList .Items;     

        // iterate list items
        foreach (SPListItem i in ItemCollection)
        {
            // perform action on individual list items here
        }
 
    }
}

There is a reasonably noticeable performance hit when using this approach, even on smallish lists.  So I decided to explore batch processing and found a brief but handy Microsoft page (Batch Updating List Items in Windows SharePoint Services 3.0) providing an example of using the SPWeb.ProcessBatchData Method.  An example of which is below:

 

StringBuilder methodBuilder = new StringBuilder();
string batch = string.Empty;

string batchFormat = “<?xml version=\”1.0\” encoding=\”UTF-8\”?><ows:Batch OnError=\”Return\”>{0}</ows:Batch>”;

string methodFormat = “<Method ID=\”{0}\”>” +
                                     
“<SetList>{1}</SetList>” +
                                     
“<SetVar Name=\”Cmd\”>Save</SetVar>” +
                                     
“<SetVar Name=\”ID\”>{2}</SetVar>” +
                                     
“<SetVar Name=\”urn:schemas-microsoft-com:office:office#FIELD_NAME\”>{3}</SetVar>” +
                                    
“</Method>”;

using (SPSite site = new SPSite(“SHAREPOINT_URL”))
{
   
using(SPWeb web= site.OpenWeb())
    {
        // get list
        SPList myList = web.Lists["LIST_NAME"];
        string listGuid = myList.ID.ToString();

        // get list items to work with
        SPListItemCollection unprocessedItems = myList.Items;

        // build caml commands
        for (int i = 0; i < unprocessedItems.Count; i++)
        {
            // get item id
           
int itemID = unprocessedItems[i].ID;

            // prevent modified date from being updated
            unprocessedItems[i].SystemUpdate(false);           

            methodBuilder.AppendFormat(methodFormat, itemID, listGuid, itemID, “FIELD_VALUE”);
        }  

        // put the pieces together.
        batch = string.Format(batchFormat, methodBuilder.ToString());

        // process batch commands.
        string batchReturn = web.ProcessBatchData(batch); 
    }
}

The above approach is certainly quicker that manually iterating the list but one important observation I have made is that is that the code will continue to execute immediately after calling the .web.ProcessBatchData() method, this may or not be important depending on what you are doing.  For example at this point I wanted to update the status field for all list items simply to indicate that another background job being handled by a windows service had been initiated that would process on every list item.  The job being handled by the windows service would update the status field again once the list item had been processed.  The problem here is that it’s quite possible that the code will continue to execute and the status could be changed by my job before the batch command has been processed.  As far as I have been able to establish it isn’t possible to monitor the progress of the batch commands as it is just passed to SharePoint to handle.

If anyone knows if there is anyway to monitor the progress of the batch commands that have been handled I would love to know, sadly I don’t think this is possible meaning that this approach is not going to be suitable for all situations.

Update a List Item Without Updating the Modified Date/Time

I recently had to update a bunch of list items, but I didn’t want to update the modified date field.  I struggled with this briefly before discovering the two update method variations.

This is the first method I was using and this WILL update the modified date field:

// update
i["CUSTOM_FIELD_NAME"] = itemData.ToString();
i.Update();

 This is the second method and it does NOT update the modified date field:

// update
i["CUSTOM_FIELD_NAME"] = itemData.ToString();
i.SystemUpdate();

The difference is just .Update() vs .SystemUpdate() with the second updating the database without effecting the date/time fields.  For more info take a look at the Microsoft SPListItem.SystemUpdate Method (Microsoft.SharePoint) page.

SharePoint Internal Field Names

So one of the very first things I needed when creating custom webparts was the internal names of some list columns (as they tend to differ from the friendly column names presented to the end user).  While you are able to get these directly by navigating within SharePoint to LOCAL SHAREPOINT > Site Settings > Site Column Gallery and then hovering over the column names to see the internal name listed as a querystring param, it’s hardly the most efficient way of accessing these names regularly.

 

What I wanted was a list of common internal column names and thankfully Frode has put a list together (which I have duplicated sans GUID below).  Take a look at Frode’s awesome list of Sharepoint Column Field ID’s for more info and to download CSV/XSL versions.

 

Also if anyone knows of any alternative ways of getting them directly from SharePoint I’d be interested to know. Continue reading ‘SharePoint Internal Field Names’

Next Page »


 

December 2009
M T W T F S S
« Nov    
 123456
78910111213
14151617181920
21222324252627
28293031