Force Left Nav To at least 200 Pixels wide
Force Body To at least 500 Pixels high
SharePoint MindsharpBlogs > Nancy Brown > Posts > Trouble in the Sandbox: a Site-Scoped ItemDeleting Event Receiver

 Single Post

Dec 20
Sandboxed Solutions are a very cool, very new feature in SharePoint 2010, a version 1.0 feature. Translation: watch out for bugs.
 
When a List Item Event Receiver is added to a SharePoint Project in a Sandboxed Solution, the associated Feature is automatically Web-scoped, and works as expected. But if the Feature scope is changed to Site, weird stuff happens. Let's consider the ItemDeleting event, which has extra weirdness.
 
The Visual Studio Event Receiver wizard has an Event Source dropdown for List Item Events:
 
SharePoint Event Receiver Wizard
 
For a List Item Event, that event source is typically a type of List, which is identified by a ListTemplateId attribute in the Receivers element:
 
Receivers Element showing ListTemplateId
 
With this setup in place, this Receiver will automatically be bound to all the Announcements-type lists in any Web where the Feature has been activated, and it will not apply to any other types of Lists. (Announcements Lists are type 104 - see the List Template Type enumeration for a rundown on these - http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splisttemplatetype.aspx.)
 
In this example, the code will simply cancel the ItemDeleting event, and direct the business user to expire the Announcement instead. That code might look like this:
 

    public override void ItemDeleting(SPItemEventProperties properties)

    {

      properties.Status = SPEventReceiverStatus.CancelWithError;

      properties.ErrorMessage = "Please expire, rather than delete.";

    }

 
As long as the Feature remains at Web scope, this works as advertised - Announcements cannot be deleted, and business users are presented with the message to expire rather than delete:
 
Standard SharePoint error page with custom message
 
Try changing to a Site-scoped Feature, and deployment succeeds the first time. But the very next deployment fails, with Visual Studio muttering (in the Output window) that retraction failed, so Visual Studio just quits right there, and throws up its hands (figuratively speaking). Curiously, this does not happen with the ItemAdding or ItemUpdating events. Weirdly, if one attempts to deploy again, (third time's a charm), the "retraction" succeeds (!?!), and deployment succeeds. Here's what happened: during the failed deployment, the Sandboxed Solution is "retracted" (that is, deactivated in the Solutions Gallery), then Visual Studio chokes on deleting it. The next time, the Solution is already deactivated, so Visual Studio just attempts to delete it, succeeds in deleting it, then succeeds in deploying the new Solution.
 
Does this Site-scoped version work? Yep, a little too well. Try to delete an Announcement, and voila, the deletion is blocked, and the message appears. Switch to another type of List, a Tasks List. Try to delete a Task item, and that deletion is blocked, and the message appears. Try to delete an item from any type of List, and the deletion is blocked. Oops. The ItemDeleting Event Receiver now applies to every list, not just whatever was specified by the ListTemplateId attribute in the Receivers element in Elements.xml.
 
Remember that Event Source dropdown list in the Visual Studio Event Receiver wizard? Event Receivers are bound to Event Hosts, which are SharePoint objects: SPContentType, SPFile, SPList, SPListItem, SPWeb, SPSite, or SPWorkflow. (BTW," bound" is just another way to say "registered".) By poking around with PowerShell, one can see where an Event Receiver is bound. It turns out that when the Feature is Web-scoped, the Item Event Receiver is actually bound to individual Lists. When the Feature is Site-scoped, the Item Event Receiver is bound to the SPSite object. Here's the Web-scoped version as seen in the SharePoint 2010 Management Shell:
 
PowerShell showing Event Receiver bound to List
 
And here's the Site-scoped version:
 
PowerShell showing the Event Receiver bound to the SPSite object
 
So, a simple workaround for the Site-scoped version is to filter the Lists in the Event Receiver code, like this:
 

    public override void ItemDeleting(SPItemEventProperties properties)

    {

      base.ItemDeleting(properties);

 

      // At the Site Scope, the event receiver is registered with

      // the Site Collection, not with individual Lists,

      // so restrict it here

      if (properties.List.BaseTemplate == SPListTemplateType.Announcements)

      {

        properties.Status = SPEventReceiverStatus.CancelWithError;

        properties.ErrorMessage = "Please expire, rather than delete.";

      }

    }

 
To alleviate the annoying deployment issue, use a PowerShell script as a pre-deployment command to retract the Sandboxed Solution, leaving Visual Studio to just carry out the deletion. (Note: "Retract" is spelled "Uninstall" in PowerShell, hence the "Uninstall-SPUserSolution" below.) Here's the PreDeploy.ps1 PowerShell script:
 

Add-PSSnapin "Microsoft.SharePoint.PowerShell"

 

$wsp = "Mindsharp.ListItemEvent.SiteScope.wsp"

$url = "http://intranet"

 

Echo "  Retracting Solution..."

Uninstall-SPUserSolution $wsp -Site $url -Confirm:$False

 
Pre-deployment commands are found on the SharePoint tab of the Project's properties. (Just double-click the Properties folder in Solution Explorer to see it.) Don’t forget to use the SysNative alias in the pre-deployment command, so that Visual Studio launches the right version of PowerShell:
 

%WINDIR%\SysNative\WindowsPowerShell\v1.0\powershell.exe -command "& '$(ProjectDir)PreDeploy.ps1'"

Pre-deployment command

More Trouble in the Sandbox: Feature Receiver code in a Site-scoped Item Event Receiver Solution
 
What if this Sandboxed Solution also needs Feature Receiver code? Typically, a Feature Receiver would just be added to the existing Feature. If this were Web-scoped, that would work. If this were a Farm Solution, that would work. However, in a Sandboxed Solution, adding a Feature Receiver to the existing Site-scoped Item Event Receiver Feature can cause the WSP to get stuck in the Solutions Gallery - really, really stuck - can't delete it from the browser, can't delete using PowerShell. (Weirdly, it can be activated and deactivated.) Manual intervention can fix this.
 
To unstick the stuck WSP, save the Feature Receiver code somewhere, then delete the Feature Receiver. Build and package the solution (these options are on the Build menu). If the Solution's configuration is Debug, the newly packaged WSP will be in the Solution's bin/debug folder. Use the Show All Files button to see it in the Solution Explorer.
 
Solution Explorer showing WSP
 
Browse to the Solutions Gallery, and upload the just-packaged WSP, (the one with no Feature Receiver code), overwriting the existing "stuck" WSP. Then deactivate and delete the WSP using the Ribbon.
 
With the stuck WSP out of the way, go back to Visual Studio, and add a new Site-scoped Feature, then add the Feature Receiver code to the new Feature. This should take care of the "stuck WSP" issue, and allow normal iterative development to keep flowing.
 
Hope that helps!


 Comments

No comment(s) to show

 Add Comment

* Required Field
Your Name *
Your Blog Url
Message Subject *
Message Body *