/// <summary>
        /// Sends exemption requests for creating a keyword.
        /// </summary>
        /// <param name="customerId">The customer ID for which the call is made.</param>
        /// <param name="service">The ad group criterion service.</param>
        /// <param name="operation">The ad group criterion operation to request exemption for.
        /// </param>
        /// <param name="exemptPolicyViolationKeys">The exemptable policy violation keys.</param>
        private static void RequestExemption(
            long customerId, AdGroupCriterionServiceClient service,
            AdGroupCriterionOperation operation, PolicyViolationKey[] exemptPolicyViolationKeys)
        {
            Console.WriteLine("Try adding a keyword again by requesting exemption for its policy "
                              + "violations.");
            PolicyValidationParameter validationParameter = new PolicyValidationParameter();

            validationParameter.ExemptPolicyViolationKeys.AddRange(exemptPolicyViolationKeys);
            operation.ExemptPolicyViolationKeys.AddRange(exemptPolicyViolationKeys);

            MutateAdGroupCriteriaResponse response = service.MutateAdGroupCriteria(
                customerId.ToString(), new[] { operation });

            Console.WriteLine($"Successfully added a keyword with resource name " +
                              $"'{response.Results[0].ResourceName}' by requesting for policy violation " +
                              $"exemption.");
        }
 /// <summary>Snippet for MutateAdGroupCriteria</summary>
 /// <remarks>
 /// This snippet has been automatically generated for illustrative purposes only.
 /// It may require modifications to work in your environment.
 /// </remarks>
 public void MutateAdGroupCriteriaRequestObject()
 {
     // Create client
     AdGroupCriterionServiceClient adGroupCriterionServiceClient = AdGroupCriterionServiceClient.Create();
     // Initialize request argument(s)
     MutateAdGroupCriteriaRequest request = new MutateAdGroupCriteriaRequest
     {
         CustomerId = "",
         Operations =
         {
             new AdGroupCriterionOperation(),
         },
         PartialFailure = false,
         ValidateOnly   = false,
     };
     // Make the request
     MutateAdGroupCriteriaResponse response = adGroupCriterionServiceClient.MutateAdGroupCriteria(request);
 }
Example #3
0
        /// <summary>Snippet for MutateAdGroupCriteriaAsync</summary>
        public async Task MutateAdGroupCriteriaAsync()
        {
            // Snippet: MutateAdGroupCriteriaAsync(string, IEnumerable<AdGroupCriterionOperation>, CallSettings)
            // Additional: MutateAdGroupCriteriaAsync(string, IEnumerable<AdGroupCriterionOperation>, CancellationToken)
            // Create client
            AdGroupCriterionServiceClient adGroupCriterionServiceClient = await AdGroupCriterionServiceClient.CreateAsync();

            // Initialize request argument(s)
            string customerId = "";
            IEnumerable <AdGroupCriterionOperation> operations = new AdGroupCriterionOperation[]
            {
                new AdGroupCriterionOperation(),
            };
            // Make the request
            MutateAdGroupCriteriaResponse response = await adGroupCriterionServiceClient.MutateAdGroupCriteriaAsync(customerId, operations);

            // End snippet
        }
Example #4
0
        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer Id.</param>
        /// <param name="adGroupId">The Google Ads ad group Id.</param>
        /// <param name="keywordId">The Google Ads keyword Id.</param>
        public void Run(GoogleAdsClient client, long customerId, long adGroupId, long keywordId)
        {
            // Get the CampaignCriterionService.
            AdGroupCriterionServiceClient adGroupCriterionService =
                client.GetService(Services.V4.AdGroupCriterionService);

            // Create the keyword for update.
            AdGroupCriterion keyword = new AdGroupCriterion()
            {
                ResourceName = ResourceNames.AdGroupCriterion(customerId, adGroupId, keywordId),
                CriterionId  = keywordId,
                Status       = AdGroupCriterionStatus.Enabled,
                FinalUrls    = { "https://www.example.com" }
            };

            AdGroupCriterionOperation keywordOperation = new AdGroupCriterionOperation()
            {
                Update     = keyword,
                UpdateMask = FieldMasks.AllSetFieldsOf(keyword)
            };

            try
            {
                // Update the keyword.
                MutateAdGroupCriteriaResponse response =
                    adGroupCriterionService.MutateAdGroupCriteria(customerId.ToString(),
                                                                  new AdGroupCriterionOperation[] { keywordOperation });

                // Display the results.
                foreach (MutateAdGroupCriterionResult criterionResult in response.Results)
                {
                    Console.WriteLine($"Keyword with resource name = " +
                                      $"'{criterionResult.ResourceName}' was updated.");
                }
            }
            catch (GoogleAdsException e)
            {
                Console.WriteLine("Failure:");
                Console.WriteLine($"Message: {e.Message}");
                Console.WriteLine($"Failure: {e.Failure}");
                Console.WriteLine($"Request ID: {e.RequestId}");
                throw;
            }
        }
        /// <summary>
        /// Removes all the ad group criteria that define the existing listing group tree for an
        /// ad group. Returns without an error if all listing group criterion are successfully
        /// removed.
        /// </summary>
        /// <param name="client">The Google Ads API client..</param>
        /// <param name="customerId">The client customer ID.</param>
        /// <param name="adGroupId">The ID of the ad group that the new listing group tree will
        /// be removed from.</param>
        /// <exception cref="GoogleAdsException">Thrown if an API request failed with one or more
        /// service errors.</exception>
        private void RemoveListingGroupTree(GoogleAdsClient client, long customerId,
                                            long adGroupId)
        {
            // Get the GoogleAdsService.
            GoogleAdsServiceClient googleAdsService = client.GetService(
                Services.V4.GoogleAdsService);

            // Get the AdGroupCriterionService.
            AdGroupCriterionServiceClient adGroupCriterionService =
                client.GetService(Services.V4.AdGroupCriterionService);

            String searchQuery = "SELECT ad_group_criterion.resource_name FROM " +
                                 "ad_group_criterion WHERE ad_group_criterion.type = LISTING_GROUP AND " +
                                 "ad_group_criterion.listing_group.parent_ad_group_criterion IS NULL " +
                                 $"AND ad_group.id = {adGroupId}";

            // Creates a request that will retrieve all listing groups where the parent ad group
            // criterion is NULL (and hence the root node in the tree) for a given ad group ID.
            SearchGoogleAdsRequest request = new SearchGoogleAdsRequest()
            {
                CustomerId = customerId.ToString(),
                PageSize   = PAGE_SIZE,
                Query      = searchQuery
            };

            // Issues the search request.
            GoogleAdsRow googleAdsRow = googleAdsService.Search(request).First();

            AdGroupCriterion adGroupCriterion = googleAdsRow.AdGroupCriterion;

            Console.WriteLine("Found ad group criterion with the resource name: '{0}'.",
                              adGroupCriterion.ResourceName);

            AdGroupCriterionOperation operation = new AdGroupCriterionOperation()
            {
                Remove = adGroupCriterion.ResourceName
            };

            MutateAdGroupCriteriaResponse response =
                adGroupCriterionService.MutateAdGroupCriteria(
                    customerId.ToString(), new AdGroupCriterionOperation[] { operation });

            Console.WriteLine($"Removed {response.Results.Count}.");
        }
Example #6
0
        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID.</param>
        /// <param name="adGroupId">The ad group ID of the ad group to which the hotel listing will
        ///     be added.</param>
        /// <param name="percentCpcBidMicroAmount">The CPC bid micro amount to be set on created
        ///     ad group criteria.</param>
        public void Run(GoogleAdsClient client, long customerId, long adGroupId,
                        long percentCpcBidMicroAmount)
        {
            // Get the AdGroupCriterionService client.
            AdGroupCriterionServiceClient adGroupCriterionService =
                client.GetService(Services.V6.AdGroupCriterionService);

            List <AdGroupCriterionOperation> operations = new List <AdGroupCriterionOperation>();

            try
            {
                // Creates the root of the tree as a SUBDIVISION node.
                string rootResourceName = AddRootNode(customerId, adGroupId, operations,
                                                      percentCpcBidMicroAmount);

                // Creates child nodes of level 1, partitioned by the hotel class info.
                string otherHotelResourceName = AddLevel1Nodes(customerId, adGroupId,
                                                               rootResourceName, operations, percentCpcBidMicroAmount);

                // Creates child nodes of level 2, partitioned by the hotel country region info.
                AddLevel2Nodes(customerId, adGroupId, otherHotelResourceName, operations,
                               percentCpcBidMicroAmount);

                // Adds the listing group and prints the resulting node resource names.
                MutateAdGroupCriteriaResponse response =
                    adGroupCriterionService.MutateAdGroupCriteria(customerId.ToString(),
                                                                  operations);

                Console.WriteLine($"Added {response.Results.Count} listing group info entities " +
                                  "with resource names:");
                foreach (MutateAdGroupCriterionResult adGroupCriterionResult in response.Results)
                {
                    Console.WriteLine($"\t{adGroupCriterionResult.ResourceName}");
                }
            }
            catch (GoogleAdsException e)
            {
                Console.WriteLine("Failure:");
                Console.WriteLine($"Message: {e.Message}");
                Console.WriteLine($"Failure: {e.Failure}");
                Console.WriteLine($"Request ID: {e.RequestId}");
                throw;
            }
        }
        /// <summary>Snippet for MutateAdGroupCriteriaAsync</summary>
        /// <remarks>
        /// This snippet has been automatically generated for illustrative purposes only.
        /// It may require modifications to work in your environment.
        /// </remarks>
        public async Task MutateAdGroupCriteriaRequestObjectAsync()
        {
            // Create client
            AdGroupCriterionServiceClient adGroupCriterionServiceClient = await AdGroupCriterionServiceClient.CreateAsync();

            // Initialize request argument(s)
            MutateAdGroupCriteriaRequest request = new MutateAdGroupCriteriaRequest
            {
                CustomerId = "",
                Operations =
                {
                    new AdGroupCriterionOperation(),
                },
                PartialFailure      = false,
                ValidateOnly        = false,
                ResponseContentType = ResponseContentTypeEnum.Types.ResponseContentType.Unspecified,
            };
            // Make the request
            MutateAdGroupCriteriaResponse response = await adGroupCriterionServiceClient.MutateAdGroupCriteriaAsync(request);
        }
 /// <summary>Snippet for MutateAdGroupCriteria</summary>
 public void MutateAdGroupCriteriaRequestObject()
 {
     // Snippet: MutateAdGroupCriteria(MutateAdGroupCriteriaRequest, CallSettings)
     // Create client
     AdGroupCriterionServiceClient adGroupCriterionServiceClient = AdGroupCriterionServiceClient.Create();
     // Initialize request argument(s)
     MutateAdGroupCriteriaRequest request = new MutateAdGroupCriteriaRequest
     {
         CustomerId = "",
         Operations =
         {
             new AdGroupCriterionOperation(),
         },
         PartialFailure      = false,
         ValidateOnly        = false,
         ResponseContentType = ResponseContentTypeEnum.Types.ResponseContentType.Unspecified,
     };
     // Make the request
     MutateAdGroupCriteriaResponse response = adGroupCriterionServiceClient.MutateAdGroupCriteria(request);
     // End snippet
 }
Example #9
0
        /// <summary>Snippet for MutateAdGroupCriteriaAsync</summary>
        public async Task MutateAdGroupCriteriaRequestObjectAsync()
        {
            // Snippet: MutateAdGroupCriteriaAsync(MutateAdGroupCriteriaRequest, CallSettings)
            // Additional: MutateAdGroupCriteriaAsync(MutateAdGroupCriteriaRequest, CancellationToken)
            // Create client
            AdGroupCriterionServiceClient adGroupCriterionServiceClient = await AdGroupCriterionServiceClient.CreateAsync();

            // Initialize request argument(s)
            MutateAdGroupCriteriaRequest request = new MutateAdGroupCriteriaRequest
            {
                CustomerId = "",
                Operations =
                {
                    new AdGroupCriterionOperation(),
                },
                PartialFailure = false,
                ValidateOnly   = false,
            };
            // Make the request
            MutateAdGroupCriteriaResponse response = await adGroupCriterionServiceClient.MutateAdGroupCriteriaAsync(request);

            // End snippet
        }
        // [END add_shopping_product_ad]

        /// <summary>
        /// Creates a new default shopping listing group for the specified ad group. A listing
        /// group is the Google Ads API representation of a "product group" described in the
        /// Google Ads user interface. The listing group will be added to the ad group using an
        /// "ad group criterion".
        /// </summary>
        /// <param name="client">The Google Ads API client.</param>
        /// <param name="customerId">The client customer ID.</param>
        /// <param name="adGroupResourceName">The resource name of the ad group that the new
        /// listing group will belong to.</param>
        /// <returns>Resource name of the newly created ad group criterion containing the
        /// listing group.</returns>
        /// <exception cref="GoogleAdsException">Thrown if an API request failed with one or more
        /// service errors.</exception>
        private string AddDefaultShoppingListingGroup(GoogleAdsClient client, long customerId,
                                                      string adGroupResourceName)
        {
            // Get the AdGroupCriterionService.
            AdGroupCriterionServiceClient adGroupCriterionService = client.GetService(
                Services.V10.AdGroupCriterionService);

            // Creates a new ad group criterion. This will contain the "default" listing group (All
            // products).
            AdGroupCriterion adGroupCriterion = new AdGroupCriterion()
            {
                AdGroup = adGroupResourceName,
                Status  = AdGroupCriterionStatus.Enabled,

                // Creates a new listing group. This will be the top-level "root" node.
                // Set the type of the listing group to be a biddable unit.
                ListingGroup = new ListingGroupInfo()
                {
                    Type = ListingGroupType.Unit
                },
                // Set the bid for products in this listing group unit.
                CpcBidMicros = 500_000L
            };

            AdGroupCriterionOperation operation = new AdGroupCriterionOperation()
            {
                Create = adGroupCriterion
            };

            MutateAdGroupCriterionResult mutateAdGroupCriteriaResult =
                adGroupCriterionService.MutateAdGroupCriteria(customerId.ToString(),
                                                              new AdGroupCriterionOperation[] { operation }).Results[0];

            Console.WriteLine("Added an ad group criterion containing a listing group with " +
                              "resource name: '{0}'.", mutateAdGroupCriteriaResult.ResourceName);
            return(mutateAdGroupCriteriaResult.ResourceName);
        }
Example #11
0
        // [END setup_remarketing]

        /// <summary>
        /// Creates an ad group criterion that targets a user list with an ad group.
        /// </summary>
        /// <param name="client">The Google Ads API client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="adGroupId">The ad group on which the user list will be targeted.</param>
        /// <param name="userListResourceName">The resource name of the user list to be
        /// targeted.</param>
        /// <returns>The resource name of the newly created ad group criterion.</returns>
        // [START setup_remarketing_1]
        private string TargetAdsInAdGroupToUserList(
            GoogleAdsClient client, long customerId, long adGroupId, string userListResourceName)
        {
            // Get the AdGroupCriterionService client.
            AdGroupCriterionServiceClient adGroupCriterionServiceClient = client.GetService
                                                                              (Services.V10.AdGroupCriterionService);

            // Create the ad group criterion targeting members of the user list.
            AdGroupCriterion adGroupCriterion = new AdGroupCriterion
            {
                AdGroup  = ResourceNames.AdGroup(customerId, adGroupId),
                UserList = new UserListInfo
                {
                    UserList = userListResourceName
                }
            };

            // Create the operation.
            AdGroupCriterionOperation adGroupCriterionOperation = new AdGroupCriterionOperation
            {
                Create = adGroupCriterion
            };

            // Add the ad group criterion, then print and return the new criterion's resource name.
            MutateAdGroupCriteriaResponse mutateAdGroupCriteriaResponse =
                adGroupCriterionServiceClient.MutateAdGroupCriteria(customerId.ToString(),
                                                                    new[] { adGroupCriterionOperation });

            string adGroupCriterionResourceName =
                mutateAdGroupCriteriaResponse.Results.First().ResourceName;

            Console.WriteLine("Successfully created ad group criterion with resource name " +
                              $"'{adGroupCriterionResourceName}' targeting user list with resource name " +
                              $"'{userListResourceName}' with ad group with ID {adGroupId}.");
            return(adGroupCriterionResourceName);
        }
        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="adGroupId">The ID of the ad group.</param>
        /// <param name="replaceExistingTree">The boolean to indicate whether to replace the
        /// existing listing group tree on the ad group, if it already exists. The example will
        /// throw a <code>LISTING_GROUP_ALREADY_EXISTS</code> error if listing group tree already
        /// exists and this option is not set to true.</param>
        // [START add_shopping_product_listing_group_tree]
        public void Run(GoogleAdsClient client, long customerId, long adGroupId,
                        bool replaceExistingTree)
        {
            // Get the AdGroupCriterionService.
            AdGroupCriterionServiceClient adGroupCriterionService =
                client.GetService(Services.V10.AdGroupCriterionService);

            try
            {
                // 1) Optional: Remove the existing listing group tree, if it already exists on the
                // ad group.
                if (replaceExistingTree)
                {
                    RemoveListingGroupTree(client, customerId, adGroupId);
                }
                // Create a list of ad group criterion to add
                List <AdGroupCriterionOperation> operations = new List <AdGroupCriterionOperation>();

                // 2) Construct the listing group tree "root" node.

                // Subdivision node: (Root node)
                AdGroupCriterion adGroupCriterionRoot = CreateListingGroupSubdivisionRoot(
                    customerId, adGroupId, -1L);

                // Get the resource name that will be used for the root node.
                // This resource has not been created yet and will include the temporary ID as
                // part of the criterion ID.
                String adGroupCriterionResourceNameRoot = adGroupCriterionRoot.ResourceName;
                operations.Add(new AdGroupCriterionOperation()
                {
                    Create = adGroupCriterionRoot
                });

                // 3) Construct the listing group unit nodes for NEW, USED and other

                // Biddable Unit node: (Condition NEW node)
                // * Product Condition: NEW
                // * CPC bid: $0.20
                AdGroupCriterion adGroupCriterionConditionNew =
                    CreateListingGroupUnitBiddable(
                        customerId,
                        adGroupId,
                        adGroupCriterionResourceNameRoot,
                        new ListingDimensionInfo()
                {
                    ProductCondition = new ProductConditionInfo()
                    {
                        Condition = ProductCondition.New
                    }
                },
                        200_000L);
                operations.Add(new AdGroupCriterionOperation()
                {
                    Create = adGroupCriterionConditionNew
                });

                // Biddable Unit node: (Condition USED node)
                // * Product Condition: USED
                // * CPC bid: $0.10
                AdGroupCriterion adGroupCriterionConditionUsed =
                    CreateListingGroupUnitBiddable(
                        customerId,
                        adGroupId,
                        adGroupCriterionResourceNameRoot,
                        new ListingDimensionInfo()
                {
                    ProductCondition = new ProductConditionInfo()
                    {
                        Condition = ProductCondition.Used
                    }
                },
                        100_000L
                        );
                operations.Add(new AdGroupCriterionOperation()
                {
                    Create = adGroupCriterionConditionUsed
                });

                // Sub-division node: (Condition "other" node)
                // * Product Condition: (not specified)
                AdGroupCriterion adGroupCriterionConditionOther =
                    CreateListingGroupSubdivision(
                        customerId,
                        adGroupId,
                        -2L,
                        adGroupCriterionResourceNameRoot,
                        new ListingDimensionInfo()
                {
                    // All sibling nodes must have the same dimension type, even if they
                    // don't contain a bid.
                    ProductCondition = new ProductConditionInfo()
                }
                        );
                // Get the resource name that will be used for the condition other node.
                // This resource has not been created yet and will include the temporary ID as
                // part of the criterion ID.
                String adGroupCriterionResourceNameConditionOther =
                    adGroupCriterionConditionOther.ResourceName;
                operations.Add(new AdGroupCriterionOperation()
                {
                    Create = adGroupCriterionConditionOther
                });

                // 4) Construct the listing group unit nodes for CoolBrand, CheapBrand and other

                // Biddable Unit node: (Brand CoolBrand node)
                // * Brand: CoolBrand
                // * CPC bid: $0.90
                AdGroupCriterion adGroupCriterionBrandCoolBrand =
                    CreateListingGroupUnitBiddable(
                        customerId,
                        adGroupId,
                        adGroupCriterionResourceNameConditionOther,
                        new ListingDimensionInfo()
                {
                    ProductBrand = new ProductBrandInfo()
                    {
                        Value = "CoolBrand"
                    }
                },
                        900_000L);
                operations.Add(new AdGroupCriterionOperation()
                {
                    Create = adGroupCriterionBrandCoolBrand
                });

                // Biddable Unit node: (Brand CheapBrand node)
                // * Brand: CheapBrand
                // * CPC bid: $0.01
                AdGroupCriterion adGroupCriterionBrandCheapBrand =
                    CreateListingGroupUnitBiddable(
                        customerId,
                        adGroupId,
                        adGroupCriterionResourceNameConditionOther,
                        new ListingDimensionInfo()
                {
                    ProductBrand = new ProductBrandInfo()
                    {
                        Value = "CheapBrand"
                    }
                },
                        10_000L);

                operations.Add(new AdGroupCriterionOperation()
                {
                    Create = adGroupCriterionBrandCheapBrand
                });

                // Biddable Unit node: (Brand other node)
                // * Brand: CheapBrand
                // * CPC bid: $0.01
                AdGroupCriterion adGroupCriterionBrandOther =
                    CreateListingGroupUnitBiddable(
                        customerId,
                        adGroupId,
                        adGroupCriterionResourceNameConditionOther,
                        new ListingDimensionInfo()
                {
                    ProductBrand = new ProductBrandInfo()
                },
                        50_000L);
                operations.Add(new AdGroupCriterionOperation()
                {
                    Create = adGroupCriterionBrandOther
                });

                // Issues a mutate request to add the ad group criterion to the ad group.
                MutateAdGroupCriteriaResponse response =
                    adGroupCriterionService.MutateAdGroupCriteria(
                        customerId.ToString(), operations);

                // Display the results.
                foreach (MutateAdGroupCriterionResult mutateAdGroupCriterionResult
                         in response.Results)
                {
                    Console.WriteLine("Added ad group criterion for listing group with resource " +
                                      $"name: '{mutateAdGroupCriterionResult.ResourceName}.");
                }
            }
            catch (GoogleAdsException e)
            {
                Console.WriteLine("Failure:");
                Console.WriteLine($"Message: {e.Message}");
                Console.WriteLine($"Failure: {e.Failure}");
                Console.WriteLine($"Request ID: {e.RequestId}");
                throw;
            }
        }
        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The customer ID for which the call is made.</param>
        /// <param name="adGroupId">ID of the ad group to which keywords are added.</param>
        /// <param name="keywordText">The keyword text to add to the ad group.</param>
        public void Run(GoogleAdsClient client, long customerId, long adGroupId,
                        string keywordText)
        {
            // Get the AdGroupCriterionServiceClient.
            AdGroupCriterionServiceClient service = client.GetService(
                Services.V5.AdGroupCriterionService);

            if (string.IsNullOrEmpty(keywordText))
            {
                keywordText = DEFAULT_KEYWORD;
            }
            // Configures the keyword text and match type settings.
            KeywordInfo keywordInfo = new KeywordInfo()
            {
                Text      = keywordText,
                MatchType = KeywordMatchType.Exact
            };

            // Constructs an ad group criterion using the keyword text info above.
            AdGroupCriterion adGroupCriterion = new AdGroupCriterion()
            {
                AdGroup = ResourceNames.AdGroup(customerId, adGroupId),
                Status  = AdGroupCriterionStatus.Paused,
                Keyword = keywordInfo
            };

            AdGroupCriterionOperation operation = new AdGroupCriterionOperation()
            {
                Create = adGroupCriterion
            };

            try
            {
                try
                {
                    // Try sending a mutate request to add the keyword.
                    MutateAdGroupCriteriaResponse response = service.MutateAdGroupCriteria(
                        customerId.ToString(), new[] { operation });
                    Console.WriteLine($"Added a keyword with resource name " +
                                      $"'{response.Results[0].ResourceName}'.");
                }
                catch (GoogleAdsException ex)
                {
                    PolicyViolationKey[] exemptPolicyViolationKeys =
                        FetchExemptPolicyViolationKeys(ex);

                    // Try sending exemption requests for creating a keyword. However, if your
                    // keyword contains many policy violations, but not all of them are exemptible,
                    // the request will not be sent.
                    RequestExemption(customerId, service, operation, exemptPolicyViolationKeys);
                }
            }
            catch (GoogleAdsException e)
            {
                Console.WriteLine("Failure:");
                Console.WriteLine($"Message: {e.Message}");
                Console.WriteLine($"Failure: {e.Failure}");
                Console.WriteLine($"Request ID: {e.RequestId}");
                throw;
            }
        }
        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="adGroupId">ID of the ad group to which targeting criteria are added.
        /// </param>
        public void Run(GoogleAdsClient client, long customerId, long adGroupId)
        {
            // Get the AdGroupCriterionService.
            AdGroupCriterionServiceClient adGroupCriterionService =
                client.GetService(Services.V10.AdGroupCriterionService);

            string adGroupResourceName = ResourceNames.AdGroup(customerId, adGroupId);

            // Creates a positive ad group criterion for gender.
            AdGroupCriterion genderAdGroupCriterion = new AdGroupCriterion()
            {
                AdGroup = adGroupResourceName,
                // Targets male.
                Gender = new GenderInfo()
                {
                    Type = GenderType.Male
                }
            };

            // Creates a negative ad group criterion for age range.
            AdGroupCriterion ageRangeNegativeAdGroupCriterion = new AdGroupCriterion()
            {
                AdGroup = adGroupResourceName,
                // Makes this ad group criterion negative.
                Negative = true,
                // Targets the age range of 18 to 24.
                AgeRange = new AgeRangeInfo()
                {
                    Type = AgeRangeType.AgeRange1824
                }
            };

            // Creates ad group criterion operations for both ad group criteria.
            AdGroupCriterionOperation[] operations = new AdGroupCriterionOperation[]
            {
                new AdGroupCriterionOperation()
                {
                    Create = genderAdGroupCriterion
                },
                new AdGroupCriterionOperation()
                {
                    Create = ageRangeNegativeAdGroupCriterion
                }
            };

            try
            {
                // Issues a mutate request to add the ad group criteria and print out some
                // information.
                MutateAdGroupCriteriaResponse response =
                    adGroupCriterionService.MutateAdGroupCriteria(
                        customerId.ToString(), operations);

                Console.WriteLine($"Added {response.Results.Count} demographic ad group" +
                                  $" criteria:");

                foreach (MutateAdGroupCriterionResult result in response.Results)
                {
                    Console.WriteLine(result.ResourceName);
                }
            }
            catch (GoogleAdsException e)
            {
                Console.WriteLine("Failure:");
                Console.WriteLine($"Message: {e.Message}");
                Console.WriteLine($"Failure: {e.Failure}");
                Console.WriteLine($"Request ID: {e.RequestId}");
                throw;
            }
        }
        /// <summary>
        /// Displays the result from the mutate operation.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="adGroupId">The ad group to which keywords are added.</param>
        /// <param name="threadIndex">The thread ID.</param>
        private async Task CreateKeyword(GoogleAdsClient client, int threadIndex, long customerId,
                                         long adGroupId)
        {
            await Task.Run(() =>
            {
                // Get the AdGroupCriterionServiceClient.
                AdGroupCriterionServiceClient adGroupCriterionService =
                    client.GetService(Services.V3.AdGroupCriterionService);

                List <AdGroupCriterionOperation> operations = new List <AdGroupCriterionOperation>();

                for (int i = 0; i < NUM_KEYWORDS; i++)
                {
                    AdGroupCriterion criterion = new AdGroupCriterion()
                    {
                        Keyword = new KeywordInfo()
                        {
                            Text      = $"mars cruise thread {threadIndex} seed {i}",
                            MatchType = KeywordMatchType.Exact
                        },
                        AdGroup = ResourceNames.AdGroup(customerId, adGroupId),
                        Status  = AdGroupCriterionStatus.Paused
                    };

                    // Creates the operation.
                    operations.Add(new AdGroupCriterionOperation()
                    {
                        Create = criterion
                    });
                }

                int retryCount        = 0;
                int retrySeconds      = 30;
                const int NUM_RETRIES = 3;

                while (retryCount < NUM_RETRIES)
                {
                    try
                    {
                        // Makes the validateOnly mutate request.
                        MutateAdGroupCriteriaResponse response =
                            adGroupCriterionService.MutateAdGroupCriteria(
                                customerId.ToString(), operations, false, true);
                        Console.WriteLine($"[{threadIndex}] Validated {operations.Count} " +
                                          $"ad group criteria:");
                        break;
                    }
                    catch (GoogleAdsException e)
                    {
                        // Checks if any of the errors are QuotaError.RESOURCE_EXHAUSTED or
                        // QuotaError.RESOURCE_TEMPORARILY_EXHAUSTED.
                        // Note: The code assumes that the developer token is approved for
                        // Standard Access.
                        if (e.Failure != null)
                        {
                            bool isRateExceededError = false;
                            e.Failure.Errors
                            .Where(err =>
                                   err.ErrorCode.QuotaError == QuotaError.ResourceExhausted ||
                                   err.ErrorCode.QuotaError == QuotaError.ResourceTemporarilyExhausted)
                            .ToList()
                            .ForEach(delegate(GoogleAdsError err)
                            {
                                Console.Error.WriteLine($"[{threadIndex}] Received rate " +
                                                        $"exceeded error. Message says, \"{err.Message}\".");
                                isRateExceededError = true;
                            }
                                     );
                            if (isRateExceededError)
                            {
                                Console.Error.WriteLine(
                                    $"[{threadIndex}] Will retry after  {retrySeconds} seconds.");
                                Thread.Sleep(retrySeconds * 1000);
                                retryCount++;
                                // Uses an exponential backoff policy to avoid polling too
                                // aggressively.
                                retrySeconds *= 2;
                            }
                        }
                        else
                        {
                            Console.WriteLine("Failure:");
                            Console.WriteLine($"Message: {e.Message}");
                            Console.WriteLine($"Failure: {e.Failure}");
                            Console.WriteLine($"Request ID: {e.RequestId}");
                            break;
                        }
                    }
                    finally
                    {
                        if (retryCount == NUM_RETRIES)
                        {
                            throw new Exception($"[{ threadIndex }] Could not recover after " +
                                                $"making {retryCount} attempts.");
                        }
                    }
                }
            });
        }