Thursday, December 20, 2007

A Tool to Help with CAS Policies

When adding Code Access Security policies to a manifest file in a SharePoint feature, determining which permissions to apply can be a hit and miss affair. Add some permissions, activate the feature and read the SecurityException to get an idea of what else is needed.

But help is already on your development machine, in the guise of PERMCALC (official known as the "Minimum Grant Set Determination tool"), a visual studio command line tool that is run from the Visual Studio Command window.

This tool is run against one or more assemblies, and generates an XML file listing the "estimated" permissions that must be granted to access that assembly. It attempts to trace all code paths through the named assembly, and through the libraries called by the assembly. So even if it doesn't give a comprehensive view, it can be a useful check before you start debugging those CAS issues.

An overview of the tool is available on the Microsoft site..

Tuesday, December 11, 2007

SPSiteDataQuery Resources

Useful posts and articles:

SPGridView Requests FileIOPermission When Added to a Web Part

I have been struggling with the SPGridView causing a security exception in a custom web part. Exploring the code with reflector reveals that when the SPGridView loads it tries to register a JavaScript file from the Templates\layouts folder in the 12 hive, and this process involves a call to the MakeBrowserCacheSafeLayoutsUrl method. That method attempts to create a unique file name for the JavaScript file. This requires that the JavaScript file is opened and read, therefore needing FileIOPermissions. If the web part is not explicitly being granted FileIOPermission in CAS, then the rendering fails.

I added the following to the manifest file that configures the CAS settings for my custom web part:

<ipermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" read="C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12;$AppDir$" write="$AppDir$" append="$AppDir$" pathdiscovery="$AppDir$">

Must admit to not being happy with hard-coding the path, but it got the web part working!

If you are wondering about the $AppDir$ parameter, I quote "it refers to the initial folder the application points to, and any subfolders". Not sure what these are for SharePoint - I tried using just $AppDir$ for the Read attribute but that did not supply the necessary access in this case (hence the hard-coded path).

Thursday, December 6, 2007

Displaying Google Search Results in the MOSS Search Center

I thought of a couple of possibilities to meet this requirement, but the only approach I could get to work satisfactorily in a short space of time was to embed a call to the Google AJAX Search API inside a content editor web part.

To achieve this, first you need a Google Search API Key which you can get from a sign up form on the Google Code site. The process creates a key that will work against a specific server URL; surprisingly, the correct key actually permits the search to work from an intranet site, not just from public-facing sites. The page displaying your key also includes some starter code to show how to use that key - nice work, Google!

I modified this code somewhat to restrict search results to New Zealand sites only by applying the following restriction to each Searcher object:

searcher.setSiteRestriction("co.nz");

Had hoped for a more generic way of restricting the search to a country, but that's all I have found so far.

Then the JavaScript code, including references to the search css file "gsearch.css" and to the API launcher, was pasted into a Content Editor control on the search results page in the search center. One addition was a querystring parsing method in JavaScript to read the search term from the "k" querystring parameter in the URL for the search results page, and to use that text in the SearchControl execute call.

Certainly not as flexible or simple a process as that explained by Arpan Shah in his blog post about rendering Microsoft Live search results in SharePoint, but a good starting point to fulfill the client's requirements.

Tuesday, December 4, 2007

Debugging SharePoint Timer Jobs

I am sure it has been written about elsewhere, but here is the way in which I have been debugging timer jobs.

Add the PDB File to the GAC
The PDB file needs to be in the GAC for debugging in Visual Studio. You can add this file through a feature manifest file, but you are unlikely to want to deploy the PDB to the GAC on your production server, so a better way on the dev server is to directly place files in the GAC. To do this, map a drive in windows explorer to

\\[your server name]\c$\windows\assembly

This bypasses the windows explorer shell special handling for this folder, and allows you to copy and paste files as normal without using GACUTIL.

In the GAC_MSIL subfolder, find the subfolder corresponding to the name of your assembly. Below there will be one or more version subfolders. Find the latests version subfolder., and copy your timer job dll and pdb file (built in debug mode!) to this folder.

If this copy action is denied, open the Services administrative tool, and STOP the Windows SharePoint Services Timer service. Apply an IISRESET from the command line, and then attempt to copy the files again - resetting those two services should remove the lock on the dll. After copying the files, make sure to restart the SharePoint Timer service!

I did have one occasion where the Timer Service "hung" whilst attempting to restart. I found that ending OWSTIMER in the Windows Task Manager cleared this hiccup.

Debugging In Visual Studio
Set a breakpoint in your timer job code, and then open the "Attach to Process" dialog from the Debug menu. Check the box at the bottom of the dialog titled "Show Processes from All User", and select OWSTIMER.EXE from the list of available processes. Click the Attach button.... and hopefully your breakpoint should display as a nice fat filled dot!

An outlined breakpoint (an empty circle) rather than a filled breakpoint means VS cannot match your code against the running code, and so something in the above process has not worked for you. Worked for me, though! Perhaps you have copied your dll and PDB files to the wrong GAC subfolder?

Triggering the Job
Now you just need to trigger your timer job. One suggestion for this is to modify the schedule of the job to occur frequently - have a look at this post on blah!bLaH!BLOG!! for how to do that.

I have a design pattern in place where the schedule for custom timer jobs are configured in a configuration list in the WSS site. When the feature containing the timer job is activated, a feature receiver reads the configuration data from the list and sets the timer job accordingly. Works nicely when you want to manipulate schedules and other data relating to the timer job.

One Last Timer Job Tip...
If you need to persist data across executions of your timer job, here's how from James Mann.