Archive

Posts Tagged ‘Development’

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();
                }
            }
        }
    }
}

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 ….-->

Issues Debugging with STSDev

November 26th, 2008 Dominick Cosgrove No comments

STSDev is a useful utility for accelerating your SharePoint Application development. The tool creates your initial project structure for you, gives the assembly a strong name (for GAC deployment) and most importantly provides a number of custom build events that facilitate deploying your solution.

A nice thing about STSDev is that it gives the developer exposure to the build events that its counterparts do not (e.g. my other friend WSPBuilder). You can really see what is going on behind the scenes which really helps when you need to get down to the nitty gritty.

One issue that I come across regularly is that when I build and deploy my solution with STSDev then try to debug it, the break point is never hit. The reason for this is that the build configuration are not configured to output the debug info. The following shows you how to fix this in Visual Studio 2008:

1. Open your STSDev created project in Visual Studio 2008;

2. From the Toolbar select Project | [Project Name] Properties…;

image

3. Select the build tab on the Project Property Page;

image

4. Scroll down to the bottom of the build page and select Advanced…;

5. On the Advanced Build Settings dialog box set the Debug Info to Full;

image

6. Click OK and rebuild and deploy your project, you should now be ready to debug your solution.

Great article on how to build documentation from Source Files

November 15th, 2008 Dominick Cosgrove No comments

XML Comments Let You Build Documentation Directly From Your Visual Studio .NET Source Files by J. Andrew Schafer

C# allows developers to embed XML comments into their source files—a useful facility, especially when more than one programmer is working on the same code. The C# parser can expand these XML tags to provide additional information and export them to an external document for further processing. This article shows how to use XML comments and explains the relevant tags. The author demonstrates how to set up your project to export your XML comments into convenient documentation for the benefit of other developers. He also shows how to use comments to generate help files.

http://msdn.microsoft.com/en-us/magazine/cc302121.aspx

Categories: Development Tags: ,

Get Assemblies from the GAC

October 9th, 2008 Dominick Cosgrove No comments

If you need to retieve an assembly from the GAC you can do this by carrying out the following:

  1. Start | Run;
  2. Enter C:\windows\assembly\GAC_MSIL into the open dialog box;
  3. There will be a folder for each assembly in the GAC locate the folder. The assembly (dll) will be in the folder.

image

Categories: Development Tags: