Reputation: 7769
Context: VS2015 Community; C#; ClearScript.V8.5.4.5; Google.AdWords.18.25.0
For background on this posting, see an earlier posting (Kudos, by the way, to @BitCortex for solving the first conundrum.)
I now have a working Adwords mutation scripted in JScript via ClearScript and C#. The challenge now is to handle errors.
In the following chunk of code, I'm creating a new 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;
}
The problem I'm having at the moment is that if there is an error, exc
doesn't have anything useful in it apart from
exc
{...}
description: ""
message: ""
name: "Error"
number: -2146190593
for example, and response
is undefined.
The usual data that would be available in a BudgetOrderReturnValue
running natively in C# is not stored anywhere I can see.
I did try casting the result of the mutate using
response = host.cast(BudgetOrderReturnValue,bos.mutate(mutations));
but when the error occurs, response
is still set as undefined.
I've been able to capture the XML for the mutate having specified
<add name="AdsClientLibs.DetailedRequestLogs" value="All" />
in App.config
which gives me a detailed_logs.log
in C:\Logs\Adwords
. Thus when an error occurs I've been able to go back to that log and see what the error was, e.g.
<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>
However, none of that data seems to be available to the script.
Ideas, anyone?
LATER
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");
}
//...
}
Unfortunately, this doesn't work. The bos.mutate line causes the script to crash with an uncaught error.
NEXT DAY
The output from the EXE running the script:
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;
})
The C# code
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);
}
The JScript code as above. So the ClearScript engine appears not to be doing well with tryCatch.
A COUPLE OF DAYS LATER
I've learned one thing at least out of this: I don't need to put
WindowsScriptEngineFlags.EnableDebugging | WindowsScriptEngineFlags.EnableJITDebugging
into my C# code when instantiating the JScriptEngine
object. If there's a debugger;
statement in the script, I'll get prompted to start a debugging session.
But back to the script
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;
}
The first time through, it works fine. The second time through, with the dates unchanged, throws an AdWords error (date range already taken) which causes the JScriptEngine to throw an unhandled exception error. I get prompted to start a debugging session which on launch shows a dialog containing
Unhandled exception at line 52, column 2 in JScript - script block
0x8013baff - unknown exception
and the highlight on the line response = bos.mutate(mutations);
. And this happens whether I've got a debugger;
statement or not.
So I'm giving up on the scripting of AdWords using ClearScript. Maybe I should file this as a bug with the folk at ClearScript.
Upvotes: 0
Views: 506
Reputation: 3548
JScript has limited support for host exception handling, but you could try 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)) { ... }
...
}
Obviously for this to work you must expose the host exception types (BudgetOrderError
et al) via ScriptEngine.AddHostType
.
Upvotes: 1