从 ClearScript 调用时在 JScript 中捕获 Adwords 错误?

Posted

技术标签:

【中文标题】从 ClearScript 调用时在 JScript 中捕获 Adwords 错误?【英文标题】:Trapping Adwords errors in JScript when called from ClearScript? 【发布时间】:2016-05-16 04:18:58 【问题描述】:

背景:VS2015社区; C#; ClearScript.V8.5.4.5; Google.AdWords.18.25.0

有关此帖子的背景信息,请参阅 earlier posting(顺便感谢 @BitCortex 解决了第一个难题。)

我现在通过 ClearScript 和 C# 在 JScript 中编写了一个有效的 Adwords 变异脚本。现在的挑战是处理错误。

在下面的代码块中,我创建了一个新的BudgetOrder

var order = new BudgetOrder();
order.billingAccountId = acct.id;
order.startDateTime = "20160801 000000 Australia/Perth";
order.endDateTime = "20160831 235959 Australia/Perth";

var amt = new Money();
amt.microAmount = 10000000;
order.spendingLimit = amt;

var boo = new BudgetOrderOperation();
boo.operator = Operator.ADD;
boo.operand = order;
var mutations = ToTypedArray(BudgetOrderOperation, [boo]);

var response;
try 
  response = bos.mutate(mutations);
  Console.WriteLine(response.value[0].billingAccountId);
  Console.WriteLine(response.value[0].id);
  Console.WriteLine(response.value[0].lastRequest.status.ToString());
 catch (exc) 
  Console.WriteLine(exc.message);


...

function ToTypedArray(typ, arr) 
  var T;
  if ("string" === typeof typ) 
    T = host.type(typ);
   else 
    T = typ;
  
  var a = host.newArr(T, arr.length);
  for (var i = 0; i < arr.length; i++) 
    a.SetValue(arr[i], i);
  
  return a;

我现在遇到的问题是,如果出现错误,exc 除了

之外没有任何用处
exc
...
    description: ""
    message: ""
    name: "Error"
    number: -2146190593

例如,response未定义

在 C# 中本机运行的 BudgetOrderReturnValue 中可用的常用数据并未存储在我能看到的任何地方。

我确实尝试使用

投射变异的结果
response = host.cast(BudgetOrderReturnValue,bos.mutate(mutations));  

但是当错误发生时,response 仍然设置为undefined

我已经能够为指定的 mutate 捕获 XML

<add name="AdsClientLibs.DetailedRequestLogs" value="All" />

App.config 中,这给了我在C:\Logs\Adwords 中的detailed_logs.log。因此,当发生错误时,我能够返回到该日志并查看错误是什么,例如

        <detail>
            <ns2:ApiExceptionFault xmlns="https://adwords.google.com/api/adwords/cm/v201603" xmlns:ns2="https://adwords.google.com/api/adwords/billing/v201603">
                <message>[BudgetOrderError.INVALID_BUDGET_DATE_RANGE @ operations[0].operand.startDateTime.endDateTime; trigger:'Overlapping budget found']</message>
                <ApplicationException.Type>ApiException</ApplicationException.Type>
                <errors xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:BudgetOrderError">
                    <fieldPath>operations[0].operand.startDateTime.endDateTime</fieldPath>
                    <trigger>Overlapping budget found</trigger>
                    <errorString>BudgetOrderError.INVALID_BUDGET_DATE_RANGE</errorString>
                    <ApiError.Type>BudgetOrderError</ApiError.Type>
                    <ns2:reason>INVALID_BUDGET_DATE_RANGE</ns2:reason>
                </errors>
            </ns2:ApiExceptionFault>
        </detail>

但是,脚本似乎没有任何数据可用。

有什么想法吗?

稍后

var response;
var hostException;
var succeeded = host.tryCatch(
    function () 
    response = bos.mutate(mutations);
    return true;
  ,
    function (exception) 
    hostException = exception;
    return false;
  );
if (succeeded) 
  // process response
  Console.WriteLine(response.value[0].billingAccountId);
  Console.WriteLine(response.value[0].id);
  Console.WriteLine(response.value[0].lastRequest.status.ToString());

 else 
  // handle host exception
  if (host.isType(BudgetOrderError, hostException)) 
    Console.WriteLine("BudgetOrderException");
   else if (host.isType(ClientTermsError, hostException)) 
    Console.WriteLine("ClientTermsError");
  
  //...

很遗憾,这不起作用。 bos.mutate 行会导致脚本因未捕获的错误而崩溃。

第二天

运行脚本的 EXE 的输出:

Exception has been thrown by the target of an invocation.
    at JScript global code (Script Document [temp]:149:0) -> var succeeded = host.tryCatch(
    function () 
    response = bos.mutate(mutations);
    return true;
  ,
    function (exception) 
    hostException = exception;
    return false;
  )

C#代码

        string script = File.ReadAllText(scriptSpec);
        try
        
            answer = JSengine.Evaluate(script);
        
        catch (ScriptEngineException see)
        
            Console.WriteLine(see.ErrorDetails);
            ScriptEngineException next = see.InnerException as ScriptEngineException;
            while (next != null)
            
                Console.WriteLine(next.ErrorDetails);
                next = next.InnerException as ScriptEngineException;
            
        
        catch (Exception exc)
        
            Console.WriteLine(exc.Message);
        

上面的 JScript 代码。因此,ClearScript 引擎似乎在 tryCatch 方面表现不佳。

几天后

我至少从中学到了一件事:我不需要把

WindowsScriptEngineFlags.EnableDebugging | WindowsScriptEngineFlags.EnableJITDebugging

在实例化 JScriptEngine 对象时进入我的 C# 代码。如果脚本中有debugger; 语句,我会收到启动调试会话的提示。

但回到脚本

    debugger;

    var CFG = new Config(Path.Combine(Settings.Item("EXEPath"), "mutator2.cfg"));

    var config = new AdWordsAppConfig();
    config.DeveloperToken = CFG.Retrieve("DeveloperToken");
    config.UserAgent = CFG.Retrieve("UserAgent");
    config.ClientCustomerId = CFG.Retrieve("CustomerID");
    config.RetryCount = 10;

    var user = new AdWordsUser(config);
    user.OAuthProvider.ClientId = CFG.Retrieve("ClientId");
    user.OAuthProvider.ClientSecret = CFG.Retrieve("ClientSecret");
    //user.OAuthProvider.AccessToken = CFG.Retrieve("AccessToken");
    user.Config.OAuth2RefreshToken = CFG.Retrieve("OAuth2RefreshToken");
    try 
      user.OAuthProvider.RefreshAccessToken();
     catch (ex) 
      Console.WriteLine("RefreshAccessToken failed.");
      Environment.Exit(1);
    

    var bos = user.GetService(AdWordsService.v201603.BudgetOrderService);
    bos = host.cast(BudgetOrderService, bos);

    //bos.RequestHeader.clientCustomerId = config.ClientCustomerId;
    //bos.RequestHeader.developerToken = config.DeveloperToken;
    //bos.RequestHeader.userAgent = config.UserAgent;

    bas = bos.getBillingAccounts();

    var order = new BudgetOrder();
    order.billingAccountId = CFG.Retrieve("BillingID");
    order.startDateTime = "20160801 000000 Australia/Perth";
    order.endDateTime = "20160830 000000 Australia/Perth";

    var amt = new Money();
    amt.microAmount = 10000000;
    order.spendingLimit = amt;

    var boo = new BudgetOrderOperation();
    boo.operator = Operator.ADD;
    boo.operand = order;
    var mutations = ToTypedArray(BudgetOrderOperation, [boo]);
    // bos.RequestHeader.validateOnly = true;

    var response;
    var hostException;

    var succeeded = host.tryCatch(
        function () 
        response = bos.mutate(mutations);
      ,
        function (exception) 
        hostException = exception;
        return true;
      );
    if (succeeded) 
      // process response
      Console.WriteLine(response.value[0].billingAccountId);
      Console.WriteLine(response.value[0].id);
      Console.WriteLine(response.value[0].lastRequest.status.ToString());

     else 
      // handle host exception
      if (host.isType(BudgetOrderError, hostException)) 
        Console.WriteLine("BudgetOrderException");
       else if (host.isType(ClientTermsError, hostException)) 
        Console.WriteLine("ClientTermsError");
      
      //...
    

    function qq(v, d) 
      if (null === v) 
        return "undefined" === typeof d ? "" : d;
       else 
        return v;
      
    

    function ToTypedArray(typ, arr) 
      var T;
      if ("string" === typeof typ) 
        T = host.type(typ);
       else 
        T = typ;
      
      var a = host.newArr(T, arr.length);
      for (var i = 0; i < arr.length; i++) 
        a.SetValue(arr[i], i);
      
      return a;
    

第一次通过,它工作正常。第二次,在日期不变的情况下,会引发 AdWords 错误(已采用日期范围),这会导致 JScriptEngine 引发未处理的异常错误。系统提示我启动调试会话,该会话在启动时会显示一个包含

的对话框
Unhandled exception at line 52, column 2 in JScript - script block
0x8013baff - unknown exception

以及response = bos.mutate(mutations); 行上的突出显示。无论我是否有 debugger; 声明,都会发生这种情况。

所以我放弃了使用 ClearScript 编写 AdWords 脚本。也许我应该将此作为一个错误提交给 ClearScript 的人员。

【问题讨论】:

奇怪。对我来说,debugger 语句什么都不做,除非我通过WindowsScriptEngineFlags 启用脚本调试。无论如何,如果您在脚本调试器(Visual Studio?)中看到未处理的异常,那么它可能没问题。从脚本引擎的角度来看,主机异常是未处理的,但是如果您继续执行,主机将捕获它并将其传递给您的处理程序函数。您的处理函数返回true,告诉ClearScript 不要重新抛出异常,因此在调试器之外不会看到崩溃。这就是它应该工作的方式。 【参考方案1】:

JScript 对主机异常处理的支持有限,但您可以尝试HostFunctions.tryCatch

var hostException;
var succeeded = host.tryCatch(
    function() 
        response = bos.mutate(mutations);
    ,
    function(exception) 
        hostException = exception;
        return true;
    
);
if (succeeded) 
    // process response
    ...

else 
    // handle host exception
    if (host.isType(BudgetOrderError, hostException))  ... 
    else if (host.isType(ClientTermsError, hostException))  ... 
    ...

显然,要使其正常工作,您必须通过 ScriptEngine.AddHostType 公开主机异常类型(BudgetOrderError 等)。

【讨论】:

我打勾是因为它应该可以工作,至少就文档而言。但是,它不起作用。我仍然收到“JScriptEngine/Script Document [temp].js 0x8013baff - 未知异常中的第 154 行第 5 列未处理的异常”错误 ... 崩溃点是`response = bos.mutate(mutations);` 您是否在调试器之外看到了崩溃?如果是这样,您确定您的处理程序(传递给tryCatch 的第二个函数)正在返回true 见“下一天”补充。我可以向您发送资源,但您必须拥有自己的 AdWords 帐户,因为我无法与您分享我的帐户。 您的 javascript 代码将两个函数传递给 host.tryCatch。第二个返回false,意思是“重新抛出异常”。它需要返回true,意思是“我已经处理了异常”。另外,一个小问题:第一个函数(调用mutate的函数)的返回值被忽略了,所以没有必要返回它。

以上是关于从 ClearScript 调用时在 JScript 中捕获 Adwords 错误?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 ClearScript 将 AdWords 公开给 JavaScript?

从java调用oracle存储过程时在mybatis mapper中映射多个out参数

[C#]VS2017使用google v8 Javascript引擎

如何修复从Delphi应用程序调用它时在C ++ DLL中的MessageBox中显示的无效字符?

调用子进程时在文件名中引用空格

使用 RoutingSession 时在 sqlalchemy 中调用了两次“get_bind”方法