Intro
Сегодня я расскажу о прототипе первого компонента под ярлычком Sapphire. Это REPL WebPart. Эта веб-часть предназначенная для производства оперативных изменений на серверной стороне SharePoint, так же для удаленного исполнения скриптов и тестирования некоторых кусков кода.
PreBody
Производство данной веб-части было инициированно в довольно таки частых потребностях исполнения серверного кода с достаточной оперативностью, в недоступности средств разработки под рукой.
Здесь есть небольшая презетнация, в которой я постарался отобразить принципы работы Repl WebPart: Sapphire Environment Repl WebPart
В добавок к слайдам расскажу о том, что веб-часть представляет собой классический хостинг Dynamic Languages Runtime языков, пока из которых доступен только Python.
Body
Далее хотелось поговорить о том, как же всё это у меня получилось, итак проект включает в себе несколько основных модулей:
- Веб-часть и контролы представления
- Хостинг языков
Далее о них поподробнее
Language Hosting
В связи с тем, что языков, которые я захочу реализовать в данном проекте является неограниченное множество, то конечно же мне необходима абстрактная фабрика для их создания, которая будет скрывать иерархию всех доступных языков и инкапсулировать их под интерфейсом:
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);
}
Отлично, далее к нашему проекту присоединяются сборки, необходимые для имплементации скриптовых языков:
- IronPython.dll
- Microsoft.Dynamic.dll
- Microsoft.Scripting.Core.dll
- Microsoft.Scripting.ExtensionAttribute.dll
- Microsoft.Scripting.dll
Всё готово для того, чтобы реализовать Python, как среду для исполнения кода, отлично, приступим:
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);
}
}
Далее немного усложним задачу, в связи с тем, что нам будет необходимо реализовать контекст для работы с SharePoint, выглядеть это должно примерно так:
[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»);
}
Для работы с объектами SharePoint в из IronPython, нам необходимо добавить несколько библиотек:
_scope.Engine.Runtime.LoadAssembly(typeof(string).Assembly);
_scope.Engine.Runtime.LoadAssembly(typeof(Uri).Assembly);
_scope.Engine.Runtime.LoadAssembly(typeof(SPList).Assembly);
Это будет основой нашей работы с динамическими языками
WebPart + WebControls
Создадим проект с помощью SPVisualDev, добавим в него feature, внутри которой создадим веб-часть Repl WebPart, всё остальные действия стандартные, однако есть небольшой нюанс, нам нужен будет объект, с помощью которого можно будет выводить строковые значения после исполнения. Я решил создать для этих целей объект с классическим названием Console, его реализация предельна проста:
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();
}
}
}
Мы будем передавать его в среду исполнения языков, а после исполнения кода опрашивать его свойство Message и выводить его содержимое в нашу веб-часть.
EndBody
Все исходники проекта доступны на github: http://github.com/butaji/Sapphire
Так же предварительную версию Sapphire.Environment (решение поставляется в WSP) можно слить на CodePlex: http://sapphire.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=34895