Posts tagged with c#

I'm trying to build a web application in ASP.NET Core MVC with C# where I can provide some benefit for Google Ad customers. I am struggeling with the part on how do I get access to the customers Ads Account Data through the Google Ads API.

What I figured out so far

  • My Application needs to be registered with Google, having an OAuth Screen (with the scope of Google Ads API), providing a ClientId and a Secret
  • I need a developer token to access the API
  • A Test Google Ad Account to not mess around with any live Ad Campaigns.

I got the OAuth ClientID and Secret, have managed to declare and setup the ASP.NET Core Identity for Google, and I am able to register in my local WebApp with a Google Account and the Login is also working.

Is the API Token to be generated by my Google for my Application, e.g. would I need a Google Ads account for my Application itself OR do I need from each of my customers a API Token to access their data? Or is there a different way to access the customers Google Ads Campaign info?

I'm trying to implement whatsapp business API but I'm getting forbidden error I think its because i dont have enough permission. I have also implemented this code on Postman its works fine there but its not working in app i dont know why?

var client = new HttpClient();         var request = new HttpRequestMessage(HttpMethod.Post, "https://graph.facebook.com/v15.0/110474688636083/messages");         request.Headers.Add("Authorization", "Bearer EAAM2wERIcIsBAFSGQD3yCSYRd5II5u7hU1859z8VcpNFlZBjJrqJUR2QrgZADHlHYSCG0zWvpYqVkFlzea9TsN1wnu8ZBZBSiEaXQu5OZAQC63ufVKZAQDHZB25CIq3TBQ9rxr2DdZB1oZBgJtia4eAEBbzqfjwJpXm9M5SZCGhDh7JbK0s1ldz2Od099jHfKrFvnQDZD");         var content = new StringContent("{\n    \"messaging_product\": \"whatsapp\",\n    \"to\": \""+WHATSAPPNO+"\",\n    \"type\": \"template\",\n    \"template\": {\n        \"name\": \"hello_world\",\n        \"language\": {\n            \"code\": \"en_US\"\n        }\n    }\n}", null, "application/json");         request.Content = content;         var response = await client.SendAsync(request);         response.EnsureSuccessStatusCode();         Console.WriteLine(await response.Content.ReadAsStringAsync()); 

thank you for your time

I have a Framework 4.8 C# app that uses ClearScript to allow JavaScript to be used as an extension language. I am able to write plugins as DLLs and attach them at runtime, viz

JSE.Script.attach = (Func<string, bool>)Attach; ...         private static bool Attach(string dllPath, string name = "")         {             var status = false;             var htc = new HostTypeCollection();             try             {                 var assem = Assembly.Load(AssemblyName.GetAssemblyName(dllPath));                 htc.AddAssembly(assem);                 if (name.Length == 0)                 {                     name = assem.FullName.Split(',')[0];                 }                 JSE.AddHostObject(name, htc); //FIXME checkout the hosttypes                 Console.Error.WriteLine($"Attached {dllPath} as {name}");                 status = true;             }             catch (ReflectionTypeLoadException rtle)             {                 foreach (var item in rtle.LoaderExceptions)                 {                     Console.Error.WriteLine(item.Message);                     T.Fail(item.Message);                 }             }             catch (FileNotFoundException fnfe)             {                 Console.Error.WriteLine(fnfe.Message);                 T.Fail(fnfe.Message);             }             catch (Exception e)             {                 Console.Error.WriteLine(e.Message);                 T.Fail(e.Message);             }             return status;         } 

This permits my scripts to have lines like

attach(".\\Plugin_GoogleAds_Metrics.dll"); H = Plugin_GoogleAds_Metrics.GoogleAds_Metrics.Historical; H.EnableTrace("GAM"); ... 

I've made a public repo of the plugin for those interested.

What's not working in this situation is that when I try to execute the plugin's GetAccountInformation method, and execution reaches the GoogleAdsServiceClient googleAdsService = client.GetService(Services.V11.GoogleAdsService); line, an error is thrown complaining about Google.Protobuf, viz

Exception has been thrown by the target of an invocation.     at JScript global code (Script [23] [temp]:5:0) -> acc = H.GetAccountInformation(auths.Item1, 7273576109, true)    at Microsoft.ClearScript.ScriptEngine.ThrowScriptError(IScriptEngineException scriptError)    at Microsoft.ClearScript.Windows.WindowsScriptEngine.ThrowScriptError(Exception exception)    at Microsoft.ClearScript.Windows.WindowsScriptEngine.<>c__DisplayClass57_0`1.<ScriptInvoke>b__0()    at Microsoft.ClearScript.ScriptEngine.ScriptInvokeInternal[T](Func`1 func)    at Microsoft.ClearScript.ScriptEngine.ScriptInvoke[T](Func`1 func)    at Microsoft.ClearScript.Windows.WindowsScriptEngine.ScriptInvoke[T](Func`1 func)    at Microsoft.ClearScript.Windows.WindowsScriptEngine.Execute(UniqueDocumentInfo documentInfo, String code, Boolean evaluate)    at Microsoft.ClearScript.Windows.JScriptEngine.Execute(UniqueDocumentInfo documentInfo, String code, Boolean evaluate)    at Microsoft.ClearScript.ScriptEngine.Evaluate(UniqueDocumentInfo documentInfo, String code, Boolean marshalResult)    at Microsoft.ClearScript.ScriptEngine.Evaluate(DocumentInfo documentInfo, String code)    at Microsoft.ClearScript.ScriptEngine.Evaluate(String documentName, Boolean discard, String code)    at Microsoft.ClearScript.ScriptEngine.Evaluate(String documentName, String code)    at Microsoft.ClearScript.ScriptEngine.Evaluate(String code)    at RulesetRunner.Program.Run(JScriptEngine& jSE, String scriptText, Config cfg, Dictionary`2 settings) in C:\Users\bugma\Source\Repos\Present\BORR\RulesetRunner\RunManagementPartials.cs:line 72 Exception has been thrown by the target of an invocation. Exception has been thrown by the target of an invocation. Could not load file or assembly 'Google.Protobuf, Version=3.15.8.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604' or one of its dependencies. The system cannot find the file specified. 

So

  1. I am using the latest Google.Ads.GoogleAds library
  2. AutoGenerateBindingRedirects has been set to true in the csproj file
  3. Add-BindingRedirect has been executed in the context of the Plugin's project
  4. The Plugin_GoogleAds_Metrics.dll is in the same folder as the Google.Protobuf.dll

Where to from here?

I need help with getting metrics for sitelink extensions. I have tried this query but no results are returned. I can see 6 sitelink extensions in the UI.

SELECT campaign.name, feed_item.attribute_values, metrics.clicks, metrics.impressions, metrics.ctr , segments.interaction_on_this_extension, segments.placeholder_type FROM feed_item WHERE segments.date BETWEEN '2022-04-10' AND '2022-05-10' ORDER BY metrics.clicks DESC LIMIT 10

The code below is what I'm currently using to generate a JSON representation of the captured data. My question is, is the use of the Google.Protobuf.Reflection.MessageDescriptor and the use of Reflection. The code appears to work. However, is there a better way to do this?

The code is called by a ClearScript-enabled JavaScript instance, thus the strings rather than longs in the parameters.

public string GenerateHistoricalMetrics(GoogleAdsClient client, string customerIdString, string locationIdsList,string languageIdString, string keywordTextsList, string pageUrl, bool debug = true) {     if (debug) Debugger.Launch();     long[] locationIds = (from id in locationIdsList.Split(',') select long.Parse(id)).ToArray();     string[] keywordTexts = keywordTextsList.Split(',');     long customerId = long.Parse(customerIdString);     long languageId = long.Parse(languageIdString);     KeywordPlanIdeaServiceClient keywordPlanIdeaService =         client.GetService(Services.V10.KeywordPlanIdeaService);     // Make sure that keywords and/or page URL were specified. The request must have     // exactly one of urlSeed, keywordSeed, or keywordAndUrlSeed set.     if (keywordTexts.Length == 0 && string.IsNullOrEmpty(pageUrl))     {         return JsonConvert.SerializeObject(new JSON() { Error = "At least one of keywords or page URL is required, but neither was specified." });     }     // Specify the optional arguments of the request as a keywordSeed, UrlSeed,     // or KeywordAndUrlSeed.     GenerateKeywordIdeasRequest request = new GenerateKeywordIdeasRequest()     {         CustomerId = customerId.ToString(),     };     if (keywordTexts.Length == 0)     {         // Only page URL was specified, so use a UrlSeed.         request.UrlSeed = new UrlSeed()         {             Url = pageUrl         };     }     else if (string.IsNullOrEmpty(pageUrl))     {         // Only keywords were specified, so use a KeywordSeed.         request.KeywordSeed = new KeywordSeed();         request.KeywordSeed.Keywords.AddRange(keywordTexts);     }     else     {         // Both page URL and keywords were specified, so use a KeywordAndUrlSeed.         request.KeywordAndUrlSeed = new KeywordAndUrlSeed         {             Url = pageUrl         };         request.KeywordAndUrlSeed.Keywords.AddRange(keywordTexts);     }     // Create a list of geo target constants based on the resource name of specified     // location IDs.     foreach (long locationId in locationIds)     {         request.GeoTargetConstants.Add(ResourceNames.GeoTargetConstant(locationId));     }     request.Language = ResourceNames.LanguageConstant(languageId);     // Set the network. To restrict to only Google Search, change the parameter below to     // KeywordPlanNetwork.GoogleSearch.     request.KeywordPlanNetwork = KeywordPlanNetwork.GoogleSearch; //.GoogleSearchAndPartners;     var list = new List<Dictionary<string, object>>();     try     {         // Generate keyword ideas based on the specified parameters.         var response =             keywordPlanIdeaService.GenerateKeywordIdeas(request);         // Iterate over the results and print its detail.         foreach (GenerateKeywordIdeaResult result in response)         {             KeywordPlanHistoricalMetrics metrics = result.KeywordIdeaMetrics;             Google.Protobuf.Reflection.MessageDescriptor descriptor = GenerateKeywordIdeaResult.Descriptor;             foreach (var field in descriptor.Fields.InDeclarationOrder())             {                 object value = field.Accessor.GetValue(result);                 if (value != null)                 {                     var props = value.GetType().GetProperties(BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.GetField | BindingFlags.Instance);                     var dict = new Dictionary<string, object>();                     foreach (string key in from prop in props                                         let key = Title(field.JsonName) + "." + prop.Name                                         where key.StartsWith("Keyword")                                         select key                     )                     {                         dict.Add(key, value);                     }                     if (dict.Count() > 0)                         list.Add(dict);                 }             }         }     }     catch (GoogleAdsException e)     {         return JsonConvert.SerializeObject(new JSON() { Error = $"Failure: Message: {e.Message}, Failure: {e.Failure}, Request ID: {e.RequestId}" });     }     return JsonConvert.SerializeObject(new JSON() { Cargo = list, Crew = resultList }); }