CodeFluent против Interop.MSScriptControl.dll

У нас был 32-битный сервис, который мы пытаемся перевести на 64-битный.

Мы использовали Interop.MSScriptControl.dll оценить VB скрипт, написанный пользователями.

Поскольку нет 64-битной версии MSScriptControl, Я создал процесс, который был вызван внутри службы. Каждый раз, когда нам нужно оценить пользовательские скрипты, мы вызываем процесс. Попробовав это решение, я обнаружил, что оно очень медленное.

Я только что обнаружил CodeFluentRuntimeClient библиотека, которая может оценить скрипт vb, а также JavaScript. Однако способ, которым он оценивает сценарий, совершенно отличается от MSScriptControl библиотека.

Я создал простую тестовую программу для оценки старого скрипта VB, написанного пользователями.

public class VBScriptEvaluator
{
    public static dynamic Evaluate(string key, string script, IDictionary<string, object> parameterValuePair)
    {
        try
        {
            using (ScriptEngine engine = new ScriptEngine(ScriptEngine.VBScriptLanguage))
            {
                ParsedScript parsed = engine.Parse(string.Format(@"Function {0}()
{1}
End Function", key, script));

                if (script.Contains("NecUserProfile"))
                    engine.SetNamedItem("NecUserProfile", @"" + "ADMIN" + @""); //Hardcoded For now
                if (parameterValuePair != null && parameterValuePair.Count > 0)
                {
                    foreach (var para in parameterValuePair)
                        engine.SetNamedItem(para.Key, para.Value);
                }
                dynamic value = parsed.CallMethod(key);
                return (value != null) ? value.ToString() : string.Empty;
            }
        }
        catch (Exception ex)
        {
            throw;
        }
    }
}

Если я использую, как это, это работает нормально:

static void Main(string[] args)
{
    string key = "necGlobalValue";
    string script = @"necGlobalValue = ""ADMIN""";
    var result = VBScriptEvaluator.Evaluate(key, script, null); //ADMIN
}

Вот так это тоже хорошо работает:

static void Main(string[] args)
{
    Dictionary<string, object> parameterValuePair = new Dictionary<string, object>();
    parameterValuePair.Add("ZINVOICE_MARGIN_0", 141615427.8);
    parameterValuePair.Add("ZINVOICE_AMTNOTLIN_0", 187260276.84);
    var script = @"If (ZINVOICE_AMTNOTLIN_0) <> 0 Then
         SERVER_FLD0000001 = Abs(ZINVOICE_MARGIN_0) / ZINVOICE_AMTNOTLIN_0
    else
        SERVER_FLD0000001 = 0
    End If";
    var key = "SERVER_FLD0000001";
    var result = VBScriptEvaluator.Evaluate(key, script, parameterValuePair);
}

В предыдущей библиотеке она автоматически определяла тип переменных, которые будут оцениваться. Я могу передать целые числа в виде строки, и она будет работать нормально.

Если я заменим значение словаря, например, с помощью ScripEngine, он потерпит неудачу:

Dictionary<string, object> parameterValuePair = new Dictionary<string, object>();
parameterValuePair.Add("ZINVOICE_MARGIN_0", "141615427.8");
parameterValuePair.Add("ZINVOICE_AMTNOTLIN_0", "187260276.84");

Кроме того, если я делаю это, я не получаю пользователя ADMIN.

string key = "necGlobalValue";
string script = @"necGlobalValue = ""NecUserProfile""";
var result = VBScriptEvaluator.Evaluate(key, script, null); // output NecUserProfile instead of ADMIN

И кстати, я пытался дать как можно больше подробностей, поэтому вопрос так долго.

1 ответ

Решение

Я сделал это, передав параметры в функцию вместо того, чтобы использовать SetNamedItem функция.

public class VBScriptEvaluator
{
    public static dynamic Evaluate(string key, string script, IDictionary<string, object> parameterValuePair = null)
    {
        try
        {
            using (ScriptEngine engine = new ScriptEngine(ScriptEngine.VBScriptLanguage))
            {
                List<object> parameters = new List<object>() { "ADMIN" };
                string extraParameters = string.Empty;
                if (parameterValuePair != null && parameterValuePair.Count > 0)
                {
                    extraParameters = "," + string.Join(",", parameterValuePair.Select(e => e.Key));
                    foreach (var para in parameterValuePair)
                        parameters.Add(para.Value);
                }
                string parsedScript = string.Format(@"Function {0}(NecUserProfile {2})
{1}
End Function", key, script, extraParameters);
                ParsedScript parsed = engine.Parse(parsedScript);

                dynamic value = parsed.CallMethod(key, parameters.ToArray());
                return (value != null) ? value.ToString() : string.Empty;
            }
        }
        catch (Exception ex)
        {
            throw;
        }
    }
}

А вот как это использовать:

Dictionary<string, object> parameterValuePair = new Dictionary<string, object>()
{
    {"Param1", 100.0 },
    {"Param2", 10.0}
};
var script = @"If (Param2) <> 0 Then
     result = Param1 + Param2
else
    result = 1 + 2
End If";
var key = "result";
var result = VBScriptEvaluator.Evaluate(key, script, parameterValuePair); // output 110
Другие вопросы по тегам