Posts Tagged ‘Sandboxed Solutions’
To ‘this’ or not to ‘this’ with the Client Object model
Recently I developed a CustomAction on a list with some client script in the CommandAction. Nothing fancy or new.
I put a .js file in the _layouts folder and referenced the file by a CustomAction with Location ‘ScriptLink’ and ScriptSrc. Put some code in the file to get some data I needed and called executeQueryAsync with two delegates like this:
clientContext.executeQueryAsync(Function.createDelegate(this, this.OnSucceeded), Function.createDelegate(this, this.OnFailed));
Deployed as a Farm solution on the environment and everything went well so far.
After this, minds changed and it had to become a sandboxed solution. Ok, let’s do it.
1. Set the Sandboxed Solution property to True on the project
2. Removed the CustomAction with Location=’ScriptLink’
3. Put the code from the js file from the _layouts folder in the CommandUIHandler’s attribute CommandAction
4. Deployed the sandboxed solution
I always use FireFox when programming and all of a sudden I received the following error:
b is undefined
![]()
and things stopped working. While in the Farm solution the CustomAction worked as expected and the OnSucceeded and OnFailed were executed.
I put in some alert statements to see where the code broke and it seemed the OnSucceeded and the OnFailed methods weren’t executed at all.
By removing the ‘this’ keyword in the createDelegate everything went well again:
clientContext.executeQueryAsync(Function.createDelegate(this, OnSucceeded), Function.createDelegate(this, OnFailed));
This behaviour seems a bit strange to me. When putting the code in a separate js file and deploying it to the _layouts folder the ‘this’ keyword can be used, but putting the exact same code in the CommandAction of CommandUIHandler the OnSucceeded and OnFailed methods can’t be found anymore using the ‘this’ keyword.
By the way, in IE you will receive the following error:
‘b’ is null or not an object

Portal for Business
Branche: Informatie technologie
Januari 2011
SharePoint consultant/developer
Voor diverse klanten van Portal for Business heeft Anita de huisstijl toegepast op intranet sites door middel van het ontwikkelen van custom masterpages en style sheets.
Een intranet bestaat bij de klanten uit meerdere web applicaties. Om globale navigatie consistent te houden op de diverse web applicaties is er een custom site map provider ontwikkeld om dit te realiseren.
Hiernaast zijn er custom ribbon buttons ontwikkeld en een news aggregator webpart. Dit webpart verzamelt nieuws items van een bepaald niveau binnen een web applicatie tot alle onderliggende subsites en toont deze items.
De genoemde functionaliteiten zijn zowel voor SharePoint Server 2010 als voor SharePoint Foundation 2010 ontwikkeld. De solutions zijn zoveel mogelijk sandboxed solutions, tenzij de gewenste functionaliteit en daarbij behorende oplossing dit niet toelaat, zoals de custom site map provider.
SharePoint Server 2010, SharePoint Foundation 2010, Visual Studio 2010, jQuery
SharePoint 2010
September 2009 – heden
SharePoint 2010 consultant/developer
Buiten MOSS 2007 is Anita ook op SharePoint 2010 gebied zeer gedreven. Vanaf december 2009 is ze actief bezig met allerlei aspecten van SharePoint 2010 en heeft veel evenementen bijgewoond op SharePoint 2010 gebied waaronder Microsoft SharePoint Connections (2 dagen) in Amsterdam en SharePoint 2010 Evolution Conference (3 dagen) in Londen.
Ter voorbereiding op het examen voor developers van SharePoint 2010 heeft Anita de nieuwe onderdelen van SharePoint 2010 uitvoerig bestudeerd en zelf uitgeprobeerd middels het schrijven van code (C#). Specifieke SharePoint 2010 onderdelen welke aan de orde zijn geweest zijn sandboxed solutions, full-trust proxies, BCS, workflows, web analytics, custom rating icons, dialogs, ribbon customizations (ook contextueel), client object model, LINQ to SharePoint en taxonomy (term store).
SharePoint 2010, Microsoft Office SharePoint Designer 2010, Visual Studio 2010, jQuery.
Documents and versioning
A nice part of document libraries and lists is the version history. Nothing new, we had it in MOSS 2007, but I previously never dived really into the version history by code.
Recently I did and discovered something that might help you out some time.
Let’s get the files of the Shared Documents folder and get all the versions by code:
SPDocumentLibrary sharedDocs = SPContext.Current.Web.Lists['Shared Documents'] as SPDocumentLibrary;
resultBox.Text = string.Empty;
foreach (SPListItem doc in sharedDocs.Items)
{
SPFileVersionCollection coll = doc.File.Versions;
if (coll.Count != 0)
{
resultBox.Text += 'Versions of ' + doc.File.Name + Environment.NewLine;
foreach (SPFileVersion version in coll)
{
resultBox.Text += 'VersionLabel: ' + version.VersionLabel + ' IsCurrentVersion: ' + version.IsCurrentVersion + Environment.NewLine;
}
}
}
Nothing quite impressive, I used the file version collection and asked some of the properties from the SPFileVersion. Here’s the result:
Notice that version 5.0 is the currently published version and a draft version 5.1 is available too.
Now let’s take a look at the version history of the file at the document library itself:
Hey, there is another version: 5.2! Why does this file not show up by code?
There is another approach to get all the versions, let’s use the versions of the list items instead of the files:
SPDocumentLibrary sharedDocs = SPContext.Current.Web.Lists['Shared Documents'] as SPDocumentLibrary;
resultBox.Text = string.Empty;
foreach (SPListItem doc in sharedDocs.Items)
{
SPListItemVersionCollection coll = doc.Versions;
resultBox.Text += 'Versions of ' + doc.Name + Environment.NewLine;
foreach (SPListItemVersion version in coll)
{
resultBox.Text += 'VersionLabel: ' + version.VersionLabel + ' IsCurrentVersion: ' + version.IsCurrentVersion + Environment.NewLine;
}
}
Notice that all the existing versions, including the current version, are displayed. Also the sorting is the other way around compared to the listing based on the file versions.
The conclusion here is that the SPFileVersionCollection only shows the versions, without the current version and the SPListItemVersionCollection shows all the versions, including the current version.
Suppose you want to delete or put all the previous versions of a file to the recycle bin, you can easily use the SPFileVersionCollection option demonstrated above. This way you don’t have to exclude the current version from your deleting code as you would with the SPListItemVersionCollection option.
Here’s an example of this:
SPDocumentLibrary sharedDocs = SPContext.Current.Web.Lists['Shared Documents'] as SPDocumentLibrary;
resultBox.Text = 'To recycle bin: ' + Environment.NewLine;
foreach (SPListItem doc in sharedDocs.Items)
{
SPFileVersionCollection coll = doc.File.Versions;
if (coll.Count != 0)
{
resultBox.Text += doc.Name + Environment.NewLine;
doc.File.Versions.RecycleAll();
}
}
The result of questioning the SPFileVersionCollection after this action:
![]()
The result of questioning the SPListItemVersionCollection after this action:

Notice that the current version of the file still exists after the recycle action. With the SPFileVersionCollection there is one version besides the actual current version, which is not listed here. This is because the actual current version is still a draft version.
With the SPListItemVersionCollection both versions are listed, the top one is the draft, the second the published version.
Full trust proxies in SharePoint 2010
Because a sandboxed solution is completely isolated to its site collection only a subset of the Microsoft.SharePoint object model can be used. Only objects that operate within the current site collection are available to you, when you are building a sandboxed solution.
Sandboxed solutions run within a special process, the Sandbox Worker Process (SPUCWorkerProcess.exe). The sandbox worker process makes sure the artifacts from the solution can be used as though they were deployed to the server itself and it will enforce the limits of a Code Access Security (CAS) policy on the contents of the solution. The following permissions will be granted to the solution by the CAS policy:
- SharePointPermission.ObjectModel
- SecurityPermission.Execution
- AspNetHostingPermission.Level = Minimal
Ofcourse you need some more functionality from time to time. Here the full trust proxy solution comes in handy.
A Proxy Class has to be deployed at Farm level and can be used by everybody within the farm.
The full trust proxy solution exists of two classes:
The first class inherits from SPProxyOperation, the second class inherits from SPProxyOperationArgs.
Both of these are located in the Micorosft.SharePoint.UserCode namespace.
The class which inherits from SPProxyOperation implements the actual operation the full trust proxy solution has to perform.
The class which inherits from SPProxyOperationArgs defines the arguments which will be passed to the operation.
Let’s make an very simple application to write a message to an eventlog. First we’ll need a full trust proxy solution to write to the event log, second a sandboxed solution (webpart) which will tell what message the full trust proxy actually has to write.
Full trust proxy solution
First define a class which inherits from the SPProxyOperationArgs:
[assembly: AllowPartiallyTrustedCallers]
namespace FullTrustProxyProject1
{
[Serializable]
public class EventLogArgs : SPProxyOperationArgs
{
public string LogMessage { get; set; }
public string LogApplication { get; set; }
public string LogLevel { get; set; }
public EventLogArgs(string logMessage, string logApplication, string logLevel)
{
this.LogMessage = logMessage;
this.LogApplication = logApplication;
this.LogLevel = logLevel;
}
}
}
As you can see this is just a class to define arguments which will be passed to the proxy operation. The class has to be Serializable and AllowPartiallyTrustedCallers has to be set, because the class is going to be used between Trust Domains.
Next the operation of the full trust proxy, the receiver of the SPProxyOperationArgs:
namespace FullTrustProxyProject1
{
public class EventLogItemCreateOperation : SPProxyOperation
{
public override object Execute(SPProxyOperationArgs args)
{
if (args != null)
{
try
{
EventLogArgs arguments = args as EventLogArgs;
string result = SPLogger.AddEventLogEntry(arguments.LogApplication, arguments.LogLevel, arguments.LogMessage);
return result;
}
catch (Exception ex)
{
return ex.ToString();
}
}
else
{
return null;
}
}
}
}
In this class the Execute method is overridden and a check is performed for the incoming args. The args are then parsed to EventLogArgs and you can access the public properties of the EventLogArgs. The Execute method returns an object.
That’s all!
Register the full trust proxy
After implementation of these two classes the proxy has to be registered at the User Code Service in SharePoint. To do this you can use PowerShell or the Object Model.
I just made a simple Windows Forms application to register, unregister and list the registered proxies:
Register:
SPUserCodeService service = SPUserCodeService.Local;
if (service != null)
{
SPProxyOperationType getEventLogItemCreationOperation = new SPProxyOperationType(“FullTrustProxyProject1, version=1.0.0.0, Culture=neutral, PublicKeyToken=db3652199d4628cd”, “FullTrustProxyProject1.EventLogItemCreateOperation”);
service.ProxyOperationTypes.Add(getEventLogItemCreationOperation);
service.Update();
label1.Text = “Updated successfully!”;
}
else
{
label1.Text = “Update failed!”;
}
Unregister:
SPUserCodeService service = SPUserCodeService.Local;
if (service != null)
{
SPProxyOperationType getEventLogItemCreationOperation = new SPProxyOperationType(“FullTrustProxyProject1, version=1.0.0.0, Culture=neutral, PublicKeyToken=db3652199d4628cd”, “FullTrustProxyProject1.EventLogItemCreateOperation”);
service.ProxyOperationTypes.Remove(getEventLogItemCreationOperation);
service.Update();
label3.Text = “Removed succesfully!”;
}
else
{
label3.Text = “Remove failed!”;
}
And list all registered proxies:
SPUserCodeService service = SPUserCodeService.Local;
if (service != null)
{
int count = service.ProxyOperationTypes.Count;
label2.Text = “Proxy count: ” + count.ToString() + Environment.NewLine ;
foreach (SPProxyOperationType item in service.ProxyOperationTypes)
{
label2.Text += “AssemblyName: ” + item.AssemblyName + Environment.NewLine + “TypeName: ” + item.TypeName + Environment.NewLine;
}
}
Create the sandboxed solution
After deploying and registering the full trust proxy it can be used in a sandboxed solution:
Just create a webpart as you normally do, make sure this is a sandboxed solution. Create some controls, e.g.:
![]()
At the button click event all you have to do is:
EventLogArgs args = new EventLogArgs(box.Text, app.Text, logLevels.SelectedValue);
results.Text = SPUtility.ExecuteRegisteredProxyOperation(“FullTrustProxyProject1, version=1.0.0.0, Culture=neutral, PublicKeyToken=db3652199d4628cd”, “FullTrustProxyProject1.EventLogItemCreateOperation”, args).ToString();
Keep in mind!
Keep in mind that the full trust proxy runs under another process than the sandboxed solution. So if you want to debug the full trust proxy attach the SPUCWorkerProcessProxy.exe, do you want to debug the sandboxed solution, attach the SPUCWorkerProcess.exe.
When you redeploy your full trust proxy solution you have to restart the User Code Service because that’s where the full trust proxy is registered, don’t forget! I did…
To restart go to the Central Administration, Application Management, Manage services on server and find the Microsoft SharePoint Foundation Sandboxed Code Service. Stop and start this service again. Another option is to use “net stop SPUserCodeV4″, and start it again by using “net start SPUserCodeV4″.
Sandboxed solutions
Sandboxed solutions are deployed to the database. This means that no files within the sandboxed solution will ever touch the file system of the server. Even dlls, xml files and aspx pages will be deployed to the database.
In Central Administration ensure that the Microsoft SharePoint Foundation Sandboxed Code Service is running on every server in the Farm where sandboxed solutions will be deployed and running.
Sandboxed solutions run within a special process, the Sandbox Worker Process (SPUCWorkerProcess.exe), part of this service.
The visually difference between a sandboxed and a farm solution in Visual Studio 2010 are:
- the property Sandboxed Solution (Project properties): true for sandboxed, false for farm solution
- AssemblyInfo.cs: [assembly: AllowPartiallyTrustedCallers()] is present in a sandboxed solution, not in a farm solution.
Sandboxed solution are wsp packages, deployed from solution gallery at site collection level by site collection administrators. The packages are isolated to site collection it is deployed to.
The solution gallery also displays resources consumed today and average usage the last 14 days.
When using sandboxed solutions a farm administrator can assign resource points to a site collection. The default quota is 300 points per day and points are calculated based on 14 different metrics:
| Resource | Description | Units | Resources per point | Limit |
| AbnormalProcessTerminationCount | Abnormally terminated process | count | 1 | 1 |
| CPUExecutionTime | CPU Execution Time for site | seconds | 3600 | 60 |
| CriticalExceptionCount | Critical Exception Events | Events | 10 | 3 |
| InvocationCount | Solution Invocation Events | Events | <TBD> | <TBD> |
| PercentProcessorTime | % CPU usage by solution | % | 85 | 100 |
| ProcessCPUCycles | Solution CPU cycles | cycles | 1×10^11 | 1×10^11 |
| ProcessHandleCount | Windows handles count | items | 10000 | 10000 |
| ProcessIOBytes | Windows handles count | items | 0 | 1×10^8 |
| ProcessThreadCount | Thread count in overall process | Thread instances | 10000 | 200 |
| ProcessVirtualBytes | Memory consumed | Bytes | 0 | 1×10^9 |
| SharePointDatabaseQueryCount | Number of SharePoint database queries | Query instances | 20 | 100 |
| SharePointDatabaseQueryTime | Elapsed time to execute query | seconds | 120 | 60 |
| UnhandledExceptionCount | Number of unhandled exceptions | Unhandled exception instances | 50 | 3 |
| UnresponsiveProcessCount | Number of unresponsive processes | Unresponsive process instances | 2 | 1 |
These metrics were chosen because they impact the health and stability of the server. The use of resources that have a higher impact on the server will cost you more points.
When the sandboxed solutions in a site collection use more than the assigned amount of points in a single day the sandboxed solutions in that particular site collection are shut down by SharePoint. This means that end users won’t be able to use the functionality of any sandboxed solution in that specific site collection until the resource points are reset. The following message will be displayed to the user:

The quota is per day, so after 24 hours the site collection will be unlocked and sandboxed solutions in that site collection can be used again. These 24 hours can be adjusted because this is a timerjob default scheduled every 24 hours: Solution Daily Usage Update.
Some important notes:
- resource quota’s can be exceeded through high usage and can be an indicator of poorly written code e.g. the UnhandledExceptionCount, but this isn’t necessarily an indicator e.g. SharePointDatabaseQueryCount.
- resource quota’s can be exceeded for a period of time, because the resource usage is calculated by timerjobs, these have to run first to update the resource usage calculation.
- resource quota’s can be adjusted. You can define a new quota template (CA, App man, Specify Quota Templates, Create a new quota template and connect this template to a site collection: CA, App man, Configure quota’s and locks, select the site collection and the quota template to use) with other settings of maximum points, but this will impact the health and stability of the server.
- sandbox code will not be terminated mid-execution.
Timerjobs involved (for every web application):
- Solution Daily Usage Update (Marks the daily boundary for sandboxed solution resource quota monitoring, every day)
- Solution Resource Usage Log Processing (Aggregates resource usage data from sandboxed solution execution, every 5 minutes)
- Solution Resource Usage Update (Records resource usage data from sandboxed solution execution, and sends email to owners of site collections that are exceeding their allotted resource quota, every 15 minutes)
The Solution Gallery displays an overview of the solutions with status (activated or not) and the used resources per solution:

Unfortunately there is no drill down on this overview, so you can’t see which resource is heavily used in a particular solution.





