Some weeks ago I startet a new private dev project.
To reach one of the goals of the project I thought about the possibility to create Sandboxed Solutions at runtime. I’ve extracted this aspect of the project to show you how to create Sandboxed Solutions on the fly.
In my demo scenario for this blog article I’d like to have a custom list that enables me to create entries in the “Edit Control Block” at runtime. For every list item that is created in the custom list a Sandboxed Solution will be created and uploaded to the solution gallery of the site collection.
Let’s have a look:
1. First we look into the solution gallery of “http://sharepoint.local”. It’s empty.
2. I’ve created my demo solution and deployed it. This solution contains a list template and list instance. The list instance is shown in the Quick Launch as “Dynamic Menu”.
3. Now I create a new entry in this list:
4. Now we look into the solution gallery:
There is a new Sandboxed Solution in it!!
5. In the Shared Documents libary I have a single file “My PDF”. Now I open the files context menu:
6. After creating a new item in the “Dynamic Menu” I get a new entry in the Edit Control Menu:
This opens a new Outlook Window with the item URL as body.
7. For every generated solution there is an entry in the Site Collection Features list:
How does it work?
1. First I’ve created a list template and list instance.
2. Then I’ve created a Event Receiver.
There are two methods:
- Utilities.RemoveSolution
- Utilities.AddSolution
3. Method “Utilities.AddSolution”
This static method creates the Sandboxed Solution.
Therefore internal non-public methods of SharePoint are invoked. This is the most interesting aspect of the demo project!
ConstructorInfo ctor = typeof(Microsoft.SharePoint.SPSolutionExporter).Assembly.GetType("Microsoft.SharePoint.Utilities.Cab.CabinetInfo").GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0]; object cabInf = ctor.Invoke(new object[] { solutionFileName }); MethodInfo[] mi = cabInf.GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); MethodInfo mi2 = null; foreach( var m in mi ) if( m.Name == "CompressDirectory" && m.GetParameters().Length == 4 ) { mi2 = m; break; }; mi2.Invoke(cabInf, new object[] { solutionDir.FullName, true, -1, null });
In the source code before this snippet I create the structure of a WSP file in a temporary folder in the file system. The shown code creates the WSP file that I upload into the solution gallery.
4. Utilities.RemoveSolution
This static method removes the solution from the solution gallery.
5. You can download the complete code from codeplex: