Проблема MSScriptControl в Windows Server 2008

Поэтому я использую MSScriptControl для запуска некоторого javascript в своем приложении и хочу получить информацию о любых ошибках, которые может вызвать скрипт.

MSScriptControl.ScriptControlClass script = new MSScriptControl.ScriptControlClass();
try
{
    script.Language = "JScript";
    script.Timeout = 15000;
    script.Eval(Code);
}
catch (Exception ex)
{
    MSScriptControl.Error err = script.Error;
    ret = new Exception("Error on line: " + err.Line + ", Description: " + err.Description);
}

Код отлично работает на моей машине для разработки, в Windows 7, и дает мне номер строки с ошибкой. Поэтому я с радостью публикую и отправляю его на рабочий компьютер, который всегда сообщает мне, что произошла ошибка в строке 0, и описание не предоставляется.

Я пытался зайти на http://www.microsoft.com/download/en/details.aspx?id=1949 чтобы загрузить последнюю версию, но установка не дала никаких результатов. Я также установил для свойства Embed Interop Types значение false, а также скопировал свой собственный файл msscript.ocx в каталог system32 на сервере Windows 2008, но ни одна из этих попыток ни к чему не привела.

У кого-нибудь есть какие-либо рекомендации?

2 ответа

Решение

Относительно проблемы вы сталкиваетесь только с некоторыми мыслями:

  • по предоставленной вами ссылке данный элемент управления не поддерживает ни Windows 7, ни Windows 2008
  • это может быть проблема безопасности в отношении COM/UAC и т. д.
  • это может быть проблемой из-за битности, если вы скомпилировали для AnyCPU, попробуйте использовать x86

Относительно возможных альтернатив:

  • Используя JScript, вы довольно легко можете создать оценщик, который поддерживается везде, где работает.NET 4 (включая Windows Server 2008).
  • Использование JInt в качестве интерпретатора JavaScript

Если вы хотите сделать это во всех нативных C# без каких-либо сторонних или "компонентных" внешних зависимостей, используйте CodeDomProvider с крошечной начальной загрузкой JScript, как это:

private static readonly MethodInfo eval = CodeDomProvider
        .CreateProvider("JScript")
        .CompileAssemblyFromSource(new CompilerParameters(), "package e{class v{public static function e(e:String):Object{return eval(e);}}}")
        .CompiledAssembly
        .GetType("e.v")
        .GetMethod("e");

private static object JsEval(string jscript)
{
    try
    {
        return eval.Invoke(null, new[] { jscript });
    }
    catch (Exception ex)
    {
        return ex;
    }
}

это создает JsEval(string) метод, который вы можете использовать в любом месте вашего кода, чтобы "оценить" строку как JavaScript (хорошо JScript)... Итак, вызов:

MessageBox.Show("" + JsEval("2 + 2")); // 4
MessageBox.Show("" + JsEval("(function(){ return 3+7; })();")); // 10
MessageBox.Show("" + JsEval("function yay(a) { return a + 1; } yay(2);")); // 3

в зависимости от вашего использования вы можете не захотеть создавать экземпляры этих участников статически. если вы хотите манипулировать сложными объектами, вам нужно создать оболочку для рефлексивного извлечения данных (или вы можете привести их в качестве соответствующего аналога JScript, но я никогда не пробовал это делать, поскольку вам нужно было бы включать сборки JScript).

Вот пример класса-обертки, который делает все, что JavaScript позволит вам делать изначально, добавление более высокоуровневой функциональности, вероятно, будет достаточно громоздким, так что вам будет лучше либо извлечь элементы в словарь / хэш-таблицу, либо альтернативно сериализовать и десериализация на другом конце

private class JsObjectWrapper : IEnumerable
{
    public readonly object jsObject;
    private static PropertyInfo itemAccessor = null;
    private static MethodInfo getEnumerator = null;

    public JsObjectWrapper(object jsObject)
    {
        this.jsObject = jsObject;

        if (itemAccessor == null) 
        {
            itemAccessor = jsObject.GetType().GetProperty("Item", new Type[] { typeof(string) });
        }

        if (getEnumerator == null)
        {
            getEnumerator = jsObject.GetType().GetInterface("IEnumerable").GetMethod("GetEnumerator");
        }
    }

    public object this[string key]
    {
        get { return itemAccessor.GetValue(jsObject, new object[] { key }); }
        set { itemAccessor.SetValue(jsObject, value, new object[] { key }); } 
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return (IEnumerator)getEnumerator.Invoke(jsObject, null);
    }
}

Вы можете увидеть это в действии, выполнив это:

var jsObj = JsEval("var x = { a:7, b:9 };");
var csObj = new JsObjectWrapper(jsObj);

MessageBox.Show("a: " + csObj["a"]);  // a: 7
MessageBox.Show("b: " + csObj["b"]);  // b: 9

csObj["yay!"] = 69;

foreach (string key in csObj)
{
    MessageBox.Show("" + key + ": " + csObj[key]); // "key": "value"
}

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

Другие вопросы по тегам