Хостинг DLR ScriptRuntime

52

Представьте себе, что к приложению можно добавить возможности обработки сценариев. При этом допускается передача значений в сценарий и из него, а приложение может пользоваться результатами работы сценария. Это именно то, что обеспечивает хостинг DLR ScriptRuntime. В настоящее время в качестве хостируемых языков сценариев поддерживаются IronPython, IronRuby и JavaScript.

Вместе со ScriptRuntime вы получаете возможность выполнения фрагментов кода или компиляции сценария, хранящихся в файле. Вы можете выбрать нужный языковый механизм и позволить DLR обнаружить его. Сценарий может быть создан в собственном или в текущем домене. Имеется возможность не только передавать значения и получать их из сценария, но также вызывать методы на динамических объектах, созданных в сценарии.

При такой степени гибкости у хостинга ScriptRuntime существуют практически бесчисленные возможности применения. В следующем примере демонстрируется один из способов использования ScriptRuntime. Предположим, что разрабатывается приложение с корзиной для покупок. Одним из обычных требований является вычисление скидки на основе определенного критерия. Эти скидки часто изменяются в связи с началом и окончанием различных торговых акций. Существует много способов удовлетворения такого требования; в данном примере показано, как это можно сделать с помощью ScriptRuntime и небольшого сценария Python.

Для простоты пусть это будет клиентским приложением Windows, хотя оно может быть частью более крупного веб-приложения или любого другого приложения. На рисунке показан пример экрана приложения:

Приложение, использующее хостинг DLR ScriptRuntime

Приложение берет ряд наименований покупок, их общую стоимость и применяет скидку на основе выбранного переключателя. В реальном приложении применялся бы несколько более изощренный способ вычисления скидки, но для данного примера достаточно и переключателей. Ниже приведен код для вычисления скидки:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Scripting.Runtime;
using Microsoft.Scripting.Hosting;

namespace DLRHost
{
    /// <summary>
    /// Описание Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {

        public Window1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            string scriptToUse;
            if (CostRadioButton.IsChecked.Value)
            {
                scriptToUse = "AmountDisc.py";
            }
            else
            {
                scriptToUse = "CountDisc.py";
            }
            ScriptRuntime scriptRuntime = ScriptRuntime.CreateFromConfiguration();
            ScriptEngine rbEng = scriptRuntime.GetEngine("Python");
            ScriptSource source = rbEng.CreateScriptSourceFromFile(scriptToUse);
            ScriptScope scope = rbEng.CreateScope();
            scope.SetVariable("prodCount", Convert.ToInt32(totalItems.Text));
            scope.SetVariable("amt", Convert.ToDecimal(totalAmt.Text));
            source.Execute(scope);
            label5.Content = scope.GetVariable("retAmt").ToString();
        }

private void button2_Click(object sender, RoutedEventArgs e)
{
    ScriptRuntime scriptRuntime = ScriptRuntime.CreateFromConfiguration();
    dynamic calcRate = scriptRuntime.UseFile("CalcTax.py");
    label6.Content = calcRate.CalcTax(Convert.ToDecimal(label5.Content)).ToString();
}
    }
}

В первой части кода просто определяется, какой сценарий должен быть применен — AmountDisc.py или CountDisc.ру. Сценарий AmountDisc.ру вычисляет скидку на основе объема покупки. Сценарий CountDisc.ру вычисляет скидку на основе количества наименований приобретенного товара.

Следующая часть кода касается установки среды ScriptRuntime. Здесь предпринимаются четыре специфических шага: создание объекта ScriptRuntime, его соответствующая настройка, создание ScriptSource и создание ScriptScope.

Объект ScriptRuntime — начальная точка, или база, хостинга. Он хранит глобальное состояние среды хостинга. ScriptRuntime создается с помощью статического метода CreateFromConfiguration. Ниже показано содержимое файла app.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="microsoft.scripting" 
             type="Microsoft.Scripting.Hosting.Configuration.Section, 
                   Microsoft.Scripting, Version=0.9.6.10, Culture=neutral, 
                   PublicKeyToken=null" 
             requirePermission="false" />
  </configSections>

  <microsoft.scripting>
    <languages>
      <language names="IronPython;Python;py" extensions=".py" 
                displayName="IronPython 2.6 Alpha" 
                type="IronPython.Runtime.PythonContext, 
                      IronPython, Version=2.6.0.1, 
                      Culture=neutral, 
                      PublicKeyToken=null" />
    </languages>

  </microsoft.scripting>
</configuration>

Код определяет раздел microsoft.scripting и устанавливает несколько свойств для механизма сценариев IronPython. Затем получается ссылка на ScriptEngine из ScriptRuntime. В данном примере указано, что нужен механизм Python, но ScriptRuntime мог бы определить это и самостоятельно — по расширению *.py сценария.

ScriptEngine проводит работы по выполнению кода сценария. Существует несколько методов для запуска сценариев из файлов либо из фрагментов кода. ScriptEngine также предоставляет ScriptSource и ScriptScope.

Объект ScriptSource — это то, что открывает доступ к сценарию. Он представляет исходный код сценария. С его помощью можно манипулировать источником сценария: загружать его с диска, разбирать по строкам и даже компилировать сценарий в объект CompiledCode. Последнее удобно, если один и тот же сценарий должен быть выполнен многократно.

Объект ScriptScope — это, по сути, пространство имен. Чтобы передать значение в сценарий и из него, потребуется привязать переменную к ScriptScope. В данном примере с помощью метода SetVariable осуществляется передача в сценарий Python переменных prodCount и amt. Эти значения берутся из текстовых полей totalItems и totalAmt. Вычисленная скидка извлекается из сценария посредством метода GetVariable. В данном примере переменная retAmt содержит искомое значение.

Пройди тесты
Лучший чат для C# программистов