SharePoint 2010 Sandboxed Solutions: Solution Validations

Posted on 12/7/2009 @ 4:34 PM in #SharePoint by | Feedback | 3290 views

In this blog post, I will dissect every aspect of sandbox solutions as they apply to SharePoint 2010. 
The below will turn into links as newer blog posts are published.

Some of the content below uses excerpts from my book on SharePoint 2010.

________________________________________________________________

Table of Contents:

    1. The definitive guide (back to table of contents).
    2. The basics of a sandbox solution
    3. Sandbox solution architecture and restrictions
    4. Sandbox solution monitoring, management and deployment 
    5. Sandbox solution validations <-- you are here
    6. Sandbox solutions full trust proxies

________________________________________________________________

Farm administrators and site collection administrators can do various things to monitor and police their sandboxed solutions. But in virtue of being pro-active, you need a different approach!

Farm administrators can be pro-active in deploying solution validators to their farm. These validators are run when a solution is uploaded to a solution gallery. If a solution fails validation, the user is shown a suitable message, and their solution cannot be activated.

If a validator is added after solutions have been activated, the validator will be called the next time the solution is executed. If a validator is updated, the solutions are validated again the next time they are executed.

Writing a solution validator is as simple as inheriting from the SPSolutionValidator class.

Once such a class is written, you need to add the solution validator to the SPUserCodeService SolutionValidators collection. This requires writing a Farm level feature or a powershell script.

You can also iterate through existing validators in the farm by executing the following powershell command:

[Microsoft.SharePoint.Administration.SPUserCodeService]::Local.solutionvalidators

Lets look at a simple solution validator. I am going to keep this simple. This solution validator will invalidate every uploaded solution. You can write real validation logic at the indicated portions in the provided code.

Start by creating a farm solution called SolutionValidator and add a class to it called "WinsmartsSolutionValidator". Add a new class in your solution, and add the code as shown below.

   1: [Guid("3014EB40-A067-4A21-BB83-B787229A7FC1")]
   2: class WinsmartsSolutionValidator : SPSolutionValidator
   3: {
   4:     private const string validatorName = "Winsmarts Solution Validator";
   5:  
   6:     public WinsmartsSolutionValidator() { }
   7:  
   8:     public WinsmartsSolutionValidator(SPUserCodeService userCodeService)
   9:         : base(validatorName, userCodeService)
  10:     {
  11:         this.Signature = 1111;
  12:     }
  13:  
  14:     public override void ValidateSolution(SPSolutionValidationProperties properties)
  15:     {
  16:         base.ValidateSolution(properties);
  17:  
  18:         // Write some validation logic here.
  19:         properties.Valid = false;
  20:  
  21:         properties.ValidationErrorMessage = "The uploaded solution is invalid";
  22:         properties.ValidationErrorUrl = "/_layouts/SolutionValidator/WinsmartsErrorPage.aspx";
  23:     }
  24:  
  25:     public override void ValidateAssembly(SPSolutionValidationProperties properties, SPSolutionFile assembly)
  26:     {
  27:         base.ValidateAssembly(properties, assembly);
  28:         properties.Valid = true;
  29:     }
  30: }

As you can see, I have a public default constructor, which is necessary for serializing and deserializing the feature during deployment. Then there is a specific overload of the constructor in which I set the signature to a number. If you wish to update the validator, it is this signature that you'll need to change. Then there are two overrides, one to validate the solution and another to validate the assembly. Under ValidateSolution, you also have access to all the files inside the solution. The idea here is that you would write some validation logic on the solution. If you set properties.Valid = false, as I am, the solution won't get activated. You would note that I am also setting a ValidationErrorUrl here. I am pointing it to a certain URL, so now I need to create an ASPX that handle that URL. So, Go ahead and add a layouts page in your solution at the specified URL. This page can be made as smart as you wish, but I am simply showing a message saying "Your Solution Validation Failed". The customizatioins for my error page aspx are shown as below:

   1: <asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
   2: Your solution failed validation.
   3: </asp:Content>
   4:  
   5: <asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
   6: Winsmarts Error Page
   7: </asp:Content>

That's basically it! Now go ahead and add a feature, alongwith a feature event receiver. The code for the feature event receiver adds the solution validator in the FeatureActivated event and removes the solution validator in the FeatureDeactivating event. The code for my feature events looks like as shown below:

   1: public override void FeatureActivated(SPFeatureReceiverProperties properties)
   2: {
   3:     SPUserCodeService.Local.SolutionValidators.Add(
   4:         new WinsmartsSolutionValidator(SPUserCodeService.Local));
   5: }
   6:  
   7: public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
   8: {
   9:     SPUserCodeService.Local.SolutionValidators.Remove(
  10:         new Guid("3014EB40-A067-4A21-BB83-B787229A7FC1"));
  11: }

The GUID you see in the FeatureDeactivating event, is the same GUID you used to decorate your SPSolutionValidator class with.

Your code is done! Your final project structure should look like this -

Also, now go ahead and press F5 to package, deploy and activate this farm-level solution.

Now, go to your site collection and upload any sandbox solution .wsp. Since we are invalidating every single .wsp, you will be able to upload the solution. But soon as you try and activate your solution, you will be greeted by the error dialog box shown below. Note that this is the same application page you deployed alongwith your SolutionValidator solution.

This gives you all the necessary flexibility in tying down Sandbox solutions. You can now be confident that sandbox solutions will work inside their respective boundaries. Boundaries! But how do I deliver any functionality in these boundaries?? What if, sometimes I need to break these boundaries that my solution requires me to do? You would do so, by creating sandbox solution full trust proxies.

Sound off but keep it civil:

Older comments..


On 6/15/2010 3:16:31 PM Bani said ..
Could you give me some examples for when to create a Solution Validator? Can it be created say to see if my objects are getting disposed properly? Can we implement this for most FxCop rules


On 9/20/2010 12:44:07 AM Luke McGregor said ..
Im having trouble attaching to the process that calls this, any idea what it is?


On 3/25/2013 6:36:33 AM Markus said ..
My Problem is that the redirection to the error page is still working, although the solution is completely removed from solution store and the GAC. Only when the Sandboxed Code Service is stopped, I'm not redirected. After the Sandboxed Code Service has been started I'm redirected again. How to solve this?