Intro

Today I will talk about the prototype of the first component under the Sapphire label. This is a REPL WebPart. This web part is intended for making operational changes on the server side of SharePoint, as well as for remote execution of scripts and testing of some pieces of code.
PreBody
The production of this web part was initiated in the rather frequent requirements of executing server code with sufficient efficiency, in the inaccessibility of development tools at hand.
Here is a small prezentnatsiya, in which I tried to display the principles of the Repl WebPart:
Sapphire Environment Repl WebPartIn addition to the slides, I’ll tell you that the web part is a classic hosting of Dynamic Languages Runtime languages, of which only Python is available.
Body
Then I wanted to talk about how I did it all, so the project includes several basic modules:
- Web part and view controls
- Language Hosting
More about them in more detail
Language Hosting
Due to the fact that the languages that I want to implement in this project is an unlimited set, then of course I need an abstract factory to create them, which will hide the hierarchy of all available languages and encapsulate them under the interface:
public interface ILanguagesFactory
{ILanguage Create (
string name);
}')
public interface ILanguage
{string Name
{ get ;
}object Execute (
string input);
void SetVar (
string name,
object value );
object GetVar (
string name);
}Great, then the assemblies necessary for the implementation of scripting languages join our project:
Everything is ready to implement Python, as an environment for executing code, great, let's start:
public class PythonLanguage : ILanguage
{private readonly ScriptScope _scope;
public string Name
{get { return "Python" ;
}}public PythonLanguage ()
{_scope = Python.CreateEngine (). CreateScope ();
}public object Execute (
string input)
{ScriptSource source = _scope.Engine.CreateScriptSourceFromString (input);
return source.Execute (_scope);
}}Next, let's complicate the task a bit, due to the fact that we will need to implement a context for working with SharePoint, it should look something like this:
[Test]
private void python_should_assume_sharepoint_variables ()
{SPWeb fakeWeb = Isolate.Fake.Instance <SPWeb> ();
Isolate.WhenCalled (() => fakeWeb.Title) .WillReturn (
"I'm fake web" );
var python = _factory.Create (
"Python" );
python.SetVar (
"__x__" ,
"123" );
python.SetVar (
"__web__" , fakeWeb);
python.Execute (
"__x__ = __web __. Title" );
var x = (
string ) python.GetVar (
"__x__" );
Assert.AreEqual (x,
"I'm fake web" );
}To work with SharePoint objects in from IronPython, we need to add several libraries:
_scope.Engine.Runtime.LoadAssembly (
typeof (
string ) .Assembly);
_scope.Engine.Runtime.LoadAssembly (
typeof (Uri) .Assembly);
_scope.Engine.Runtime.LoadAssembly (
typeof (SPList) .Assembly);
This will be the basis of our work with dynamic languages.
WebPart + WebControls
Let's create a project using SPVisualDev, add a feature to it, inside which we will create a Repl WebPart web part, all other actions are standard, however there is a small nuance, we will need an object with which we can output string values after execution. I decided to create an object with the classic name Console for these purposes, its implementation is extremely simple:
public class Console{private readonly StringBuilder _messageBuilder =
new StringBuilder ();
public void Write (
object message)
{_messageBuilder.Append (message);
}public void WriteLine (
object message)
{_messageBuilder.AppendLine (message.ToString ());
}public string Message
{get{return _messageBuilder.ToString ();
}}}We will transmit it to the language execution environment, and after the execution of the code, poll its Message property and display its content in our web part.
Endody
All project sources are available on github:
http://github.com/butaji/SapphireThe same preliminary version of Sapphire.Environment (solution supplied in WSP) can be merged onto CodePlex:
http://sapphire.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=34895