Thursday, March 24, 2011

Full trust proxy in SharePoint sandbox solution

You know that sandbox solution in SharePoint 2010 has certain limitation like
• It doesn’t allow using web services.
• You can’t access SharePoint web controls
• It won’t allow executing code that runs under elevated privileges etc…
So, basically sandbox solution provides restricted environment to execute your code for specific SharePoint site.

What if you want to execute a web service inside a sandbox solution? The solution is to write a full trust proxy. Let’s solidify this requirement by creating a web part that gets the data from a web part. I’m going to write a simple sandbox solution that displays xml string returned from Lists.GetList(“your list name”) method.

There are three parts of this code.
• Create a proxy: This will execute your sharepoint web service and return xml
• Register full trust proxy.
• Write a web part

Create a proxy
1. Add a class library project to your solution say “RVProxy”.
2. Add a class file inside it say “ServiceHelper.cs”.
3. Copy and paste below code to your ServiceHelper.cs file

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.UserCode;
using System.Xml;

[assembly: System.Security.AllowPartiallyTrustedCallersAttribute()]
namespace RVProxy
{
public class ServiceHelper:SPProxyOperation
{
public override object Execute(SPProxyOperationArgs args)
{
if (args != null)
{
ListArgs lstArg = args as ListArgs;
string listName = lstArg.ListName;
RVListOperation.Lists lst = new RVListOperation.Lists();
lst.PreAuthenticate = true;
lst.Credentials = System.Net.CredentialCache.DefaultCredentials;
XmlNode node = lst.GetList(listName);
return node.InnerXml;
}
else
{
return null;
}
}
}

[Serializable]
public class ListArgs:SPProxyOperationArgs
{
public ListArgs(string listName)
{
this.ListName = listName;
}
public string ListName
{
get;
set;
}

}
}

In the above code, note that assembly has been tagged with attribute [assembly: System.Security.AllowPartiallyTrustedCallersAttribute()]. This tells the compiler to execute the assembly in partially trusted environment.

Class ServiceHelper inherits SPProxyOperation class. Implement its Execute() method. This method contains all the code that runs under trusted mode.

Class ListArgs serves as an input argument sent to the proxy. Don’t forget to decorate this class with attribute [Serializable]


Now your proxy is ready. You need to register this as full trust proxy.
Register full trust proxy
1. Put the “RVProxy” dll into the GAC.
2. Register this dll as full trust proxy. You can either register this using powershell script or using SharePoint object model. I’ll explain the second one here
a. Create a windows application
b. Use below code to register, unregister or view registered assemblies:
Register
private void RegisterFullTrustProxty(string assemblyName, string typeName)
{
label1.Text = "";
lblRegisteredProxy.Text = "";
SPUserCodeService service = SPUserCodeService.Local;
if (service != null)
{
SPProxyOperationType getEventLogItemCreationOperation = new SPProxyOperationType(assemblyName, typeName);
service.ProxyOperationTypes.Add(getEventLogItemCreationOperation);
service.Update();
label1.Text = "Updated successfully!";
}
else
{
label1.Text = "Update failed!";
} 
}
For e.g RegisterFullTrustProxty("RVProxy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0d35956c4346f2f1"
, "RVProxy.ServiceHelper"
);

Unregister
private void UnregisterFullTrustProxty(string assemblyName, string typeName)
{
label1.Text = "";
lblRegisteredProxy.Text = "";
SPUserCodeService service = SPUserCodeService.Local;
if (service != null)
{
SPProxyOperationType getEventLogItemCreationOperation = new SPProxyOperationType(assemblyName, typeName);
service.ProxyOperationTypes.Remove(getEventLogItemCreationOperation);
service.Update();
label1.Text = "Removed succesfully!";
}
else
{
label1.Text = "Remove failed!";
} 
}

View all registered assemblies
private void ViewAllRegisteredProxy()
{
label1.Text = "";
lblRegisteredProxy.Text = "";
SPUserCodeService service = SPUserCodeService.Local;
if (service != null)
{
int count = service.ProxyOperationTypes.Count;
lblRegisteredProxy.Text = "Proxy count: " + count.ToString() + Environment.NewLine ;
foreach (SPProxyOperationType item in service.ProxyOperationTypes)
{
lblRegisteredProxy.Text += "AssemblyName: " + item.AssemblyName + Environment.NewLine + "TypeName: " + item.TypeName + Environment.NewLine;
}
}
}
Write the web part
You have created the proxy as well as registered as a full trust proxy. Now it’s time to utilize this proxy in your web part code. I’m pasting here a sample code that utilizes the above proxy:

[ToolboxItemAttribute(false)]
public class DemoPart : WebPart
{
Label lbl = new Label();
Button btnTest = new Button()
{
Text = "Get List"
public DemoPart()
{
btnTest.Click += new EventHandler(btnTest_Click); 
}

void btnTest_Click(object sender, EventArgs e)
{
string assemblyName = "RVProxy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0d35956c4346f2f1";
string typeName = "RVProxy.ServiceHelper";
string listInfo = SPUtility.ExecuteRegisteredProxyOperation(assemblyName, typeName, new ListArgs("Tasks")).ToString();
lbl.Text += listInfo;
}
protected override void CreateChildControls()
{
lbl.Text = "Hi Ranvijay, here is your web part under sandbox solution.";
Controls.Add(lbl);
Controls.Add(btnTest);
}
Note: The proxy runs under SPUserCodeService.exe service. So, every time you make changes to your proxy and redeploy the dll to GAC, you will need to restart the “SPUserCodeV4”. To stop use "net stop SPUserCodeV4" and to start use "net start SPUserCodeV4"

No comments:

Post a Comment