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