我们尝试将32位服务迁移到64位。
我们使用Interop.MSScriptControl.dll
来评估用户编写的vb脚本。
由于MSScriptControl
没有64位版本。我创建了一个在服务中调用的进程。每次我们需要评估用户脚本时,我们都会调用该过程。在尝试此解决方案后,我发现它确实很慢。
我刚刚发现了可以评估vb脚本和JavaScript的CodeFluentRuntimeClient
库。但是,它评估脚本的方式与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
顺便说一下,我试图提供尽可能多的细节,这就是为什么问题很长的原因。
答案 0 :(得分: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