Ad Extensions in C#

 

The following example shows how to add, get, and delete extensions for an account’s ad extension library, set, get, and delete the extension associations with a campaign, and determine why an extension failed editorial review using the following Campaign Management service operations.

This example has been developed and run within the environment described in Getting Started Using C# with Bing Ads Services. To get started developing Bing Ads applications with a .NET language, Installing the SDK and either start with the provided examples or follow one of the application walkthroughs for a Web or Desktop application.

Note: This example uses the UserName and Password elements for authentication. For Managing User Authentication with OAuth, replace the UserName and Password elements with the AuthenticationToken, which is your OAuth access token.

using System;
using System.IO;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Threading.Tasks;
using Microsoft.BingAds.V10.CampaignManagement;
using Microsoft.BingAds;

namespace BingAdsExamplesConsole.V10
{
    /// <summary>
    /// This example demonstrates how to add, get, and delete extensions for an account’s ad extension library, 
    /// set, get, and delete the extension associations with a campaign, and determine why an extension failed 
    /// editorial review.
    /// </summary>
    public class AdExtensions
    {
        public static ServiceClient<ICampaignManagementService> Service;

        public string Description
        {
            get { return "Ad Extensions | Campaign Management V10"; }
        }

        /// <summary>
        /// The entry point for the console application.
        /// </summary>
        /// <param name="args">Arguments are not required for this example.</param>
        public static void Main(string[] args)
        {
            var example = new AdExtensions();
            Console.WriteLine(example.Description);
            try
            {
                var authentication = new PasswordAuthentication(
                    "<UserNameGoesHere>",
                    "<PasswordGoesHere>");

                var authorizationData = new AuthorizationData
                {
                    Authentication = authentication,
                    CustomerId = <CustomerIdGoesHere>,
                    AccountId = <AccountIdGoesHere>,
                    DeveloperToken = "<DeveloperTokenGoesHere>"
                };

                example.RunAsync(authorizationData).Wait();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// Write to the console by default.
        /// </summary>
        /// <param name="msg">The message to send as output.</param>
        private void OutputStatusMessage(String msg)
        {
            Console.WriteLine(msg);
        }

        public async Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                Service = new ServiceClient<ICampaignManagementService>(authorizationData);

                // Add a campaign that will later be associated with ad extensions. 

                var campaigns = new[] {
                    new Campaign
                    {
                        Id = null,
                        Name = "Women's Shoes " + DateTime.UtcNow,
                        Description = "Red shoes line.",
                        BudgetType = BudgetLimitType.MonthlyBudgetSpendUntilDepleted,
                        MonthlyBudget = 1000.00,
                        TimeZone = "PacificTimeUSCanadaTijuana",
                        DaylightSaving = true,

                        // Used with FinalUrls shown in the sitelinks that we will add below.
                        TrackingUrlTemplate =
                            "http://tracker.example.com/?season={_season}&promocode={_promocode}&u={lpurl}"
                    }
                };

                AddCampaignsResponse addCampaignsResponse = await AddCampaignsAsync(authorizationData.AccountId, campaigns);
                long?[] campaignIds = addCampaignsResponse.CampaignIds.ToArray();

                // Specify the extensions.

                var adExtensions = new AdExtension[] {
                    new AppAdExtension
                    {
                        AppPlatform = "Windows",
                        AppStoreId = "AppStoreIdGoesHere",
                        DestinationUrl = "DestinationUrlGoesHere",
                        DisplayText = "Contoso",
                    },
                    new CallAdExtension {
                        CountryCode = "US",
                        PhoneNumber = "2065550100",
                        IsCallOnly = false
                    },
                    new LocationAdExtension {
                        PhoneNumber = "206-555-0100",
                        CompanyName = "Contoso Shoes",
                        IconMediaId = null,
                        ImageMediaId = null,
                        Address = new Address {
                            StreetAddress = "1234 Washington Place",
                            StreetAddress2 = "Suite 1210",
                            CityName = "Woodinville",
                            ProvinceName = "WA",
                            CountryCode = "US",
                            PostalCode = "98608"
                        }
                    },
                    new SiteLinksAdExtension {
                        SiteLinks = new [] {
                            new SiteLink
                            {
                                DisplayText = "Women's Shoe Sale 1",

                                // If you are currently using Destination URLs, you must replace them with Final URLs. 
                                // Here is an example of a DestinationUrl you might have used previously. 
                                // DestinationUrl = "http://www.contoso.com/womenshoesale/?season=spring&promocode=PROMO123",

                                // To migrate from DestinationUrl to FinalUrls for existing sitelinks, you can set DestinationUrl
                                // to an empty string when updating the sitelink. If you are removing DestinationUrl,
                                // then FinalUrls is required.
                                // DestinationUrl = "",

                                // With FinalUrls you can separate the tracking template, custom parameters, and 
                                // landing page URLs. 
                                FinalUrls = new[] {
                                    "http://www.contoso.com/womenshoesale"
                                },
                                // Final Mobile URLs can also be used if you want to direct the user to a different page 
                                // for mobile devices.
                                FinalMobileUrls = new[] {
                                    "http://mobile.contoso.com/womenshoesale"
                                }, 
                                // You could use a tracking template which would override the campaign level
                                // tracking template. Tracking templates defined for lower level entities 
                                // override those set for higher level entities.
                                // In this example we are using the campaign level tracking template.
                                TrackingUrlTemplate = null,

                                // Set custom parameters that are specific to this sitelink, 
                                // and can be used by the sitelink, ad group, campaign, or account level tracking template. 
                                // In this example we are using the campaign level tracking template.
                                UrlCustomParameters = new CustomParameters {
                                    Parameters = new[] {
                                        new CustomParameter(){
                                            Key = "promoCode",
                                            Value = "PROMO1"
                                        },
                                        new CustomParameter(){
                                            Key = "season",
                                            Value = "summer"
                                        },
                                    }
                                },
                            },
                        new SiteLink
                            {
                                DisplayText = "Women's Shoe Sale 2",

                                // If you are currently using Destination URLs, you must replace them with Final URLs. 
                                // Here is an example of a DestinationUrl you might have used previously. 
                                // DestinationUrl = "http://www.contoso.com/womenshoesale/?season=spring&promocode=PROMO123",

                                // To migrate from DestinationUrl to FinalUrls for existing sitelinks, you can set DestinationUrl
                                // to an empty string when updating the sitelink. If you are removing DestinationUrl,
                                // then FinalUrls is required.
                                // DestinationUrl = "",

                                // With FinalUrls you can separate the tracking template, custom parameters, and 
                                // landing page URLs. 
                                FinalUrls = new[] {
                                    "http://www.contoso.com/womenshoesale"
                                },
                                // Final Mobile URLs can also be used if you want to direct the user to a different page 
                                // for mobile devices.
                                FinalMobileUrls = new[] {
                                    "http://mobile.contoso.com/womenshoesale"
                                }, 
                                // You could use a tracking template which would override the campaign level
                                // tracking template. Tracking templates defined for lower level entities 
                                // override those set for higher level entities.
                                // In this example we are using the campaign level tracking template.
                                TrackingUrlTemplate = null,

                                // Set custom parameters that are specific to this sitelink, 
                                // and can be used by the sitelink, ad group, campaign, or account level tracking template. 
                                // In this example we are using the campaign level tracking template.
                                UrlCustomParameters = new CustomParameters {
                                    Parameters = new[] {
                                        new CustomParameter(){
                                            Key = "promoCode",
                                            Value = "PROMO2"
                                        },
                                        new CustomParameter(){
                                            Key = "season",
                                            Value = "summer"
                                        },
                                    }
                                },
                            }
                        }
                    }
                };

                // Add all extensions to the account's ad extension library
                var adExtensionIdentities = await AddAdExtensionsAsync(
                    authorizationData.AccountId,
                    adExtensions
                    );

                OutputStatusMessage("Added ad extensions.\n\n");

                // DeleteAdExtensionsAssociations, SetAdExtensionsAssociations, and GetAdExtensionsEditorialReasons 
                // operations each require a list of type AdExtensionIdToEntityIdAssociation.
                var adExtensionIdToEntityIdAssociations = new AdExtensionIdToEntityIdAssociation[adExtensionIdentities.Count];

                // GetAdExtensionsByIds requires a list of type long.
                var adExtensionIds = new long[adExtensionIdentities.Count];

                // Loop through the list of extension IDs and build any required data structures
                // for subsequent operations. 

                for (int i = 0; i < adExtensionIdentities.Count; i++)
                {
                    adExtensionIdToEntityIdAssociations[i] = new AdExtensionIdToEntityIdAssociation
                    {
                        AdExtensionId = adExtensionIdentities[i].Id,
                        EntityId = (long)campaignIds[0]
                    };

                    adExtensionIds[i] = adExtensionIdentities[i].Id;
                }

                // Associate the specified ad extensions with the respective campaigns or ad groups. 
                await SetAdExtensionsAssociationsAsync(
                    authorizationData.AccountId,
                    adExtensionIdToEntityIdAssociations,
                    AssociationType.Campaign
                    );

                OutputStatusMessage("Set ad extension associations.\n\n");

                // Get editorial rejection reasons for the respective ad extension and entity associations.
                var adExtensionEditorialReasonCollection =
                    (AdExtensionEditorialReasonCollection[])await GetAdExtensionsEditorialReasons(
                        authorizationData.AccountId,
                        adExtensionIdToEntityIdAssociations,
                        AssociationType.Campaign
                        );

                const AdExtensionsTypeFilter adExtensionsTypeFilter = AdExtensionsTypeFilter.AppAdExtension |
                                                                      AdExtensionsTypeFilter.CallAdExtension |
                                                                      AdExtensionsTypeFilter.LocationAdExtension |
                                                                      AdExtensionsTypeFilter.SiteLinksAdExtension;

                // Get the specified ad extensions from the account’s ad extension library.
                adExtensions = (AdExtension[])await GetAdExtensionsByIdsAsync(
                    authorizationData.AccountId,
                    adExtensionIds,
                    adExtensionsTypeFilter
                    );

                OutputAdExtensionsWithEditorialReasons(adExtensions, adExtensionEditorialReasonCollection);

                // Remove the specified associations from the respective campaigns or ad groups. 
                // The extesions are still available in the account's extensions library. 
                await DeleteAdExtensionsAssociationsAsync(
                    authorizationData.AccountId,
                    adExtensionIdToEntityIdAssociations,
                    AssociationType.Campaign
                    );

                OutputStatusMessage("Deleted ad extension associations.\n\n");

                // Deletes the ad extensions from the account’s ad extension library.
                await DeleteAdExtensionsAsync(
                    authorizationData.AccountId,
                    adExtensionIds
                    );

                OutputStatusMessage("Deleted ad extensions.\n\n");
            }
            // Catch authentication exceptions
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Campaign Management service exceptions
            catch (FaultException<Microsoft.BingAds.V10.CampaignManagement.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.V10.CampaignManagement.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.V10.CampaignManagement.EditorialApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
        }

        // Adds one or more campaigns to the specified account.

        private async Task<AddCampaignsResponse> AddCampaignsAsync(long accountId, IList<Campaign> campaigns)
        {
            var request = new AddCampaignsRequest
            {
                AccountId = accountId,
                Campaigns = campaigns
            };

            return (await Service.CallAsync((s, r) => s.AddCampaignsAsync(r), request));
        }

        // Adds one or more ad extensions to the account's ad extension library.

        private async Task<IList<AdExtensionIdentity>> AddAdExtensionsAsync(long accountId, IList<AdExtension> adExtensions)
        {
            var request = new AddAdExtensionsRequest
            {
                AccountId = accountId,
                AdExtensions = adExtensions
            };

            return (await Service.CallAsync((s, r) => s.AddAdExtensionsAsync(r), request)).AdExtensionIdentities;
        }

        // Deletes one or more ad extensions from the account’s ad extension library.

        private async Task DeleteAdExtensionsAsync(long accountId, IList<long> adExtensionIds)
        {
            var request = new DeleteAdExtensionsRequest
            {
                AccountId = accountId,
                AdExtensionIds = adExtensionIds
            };

            await Service.CallAsync((s, r) => s.DeleteAdExtensionsAsync(r), request);
        }

        // Associates one or more extensions with the corresponding campaign or ad group entities.

        private async Task SetAdExtensionsAssociationsAsync(long accountId, IList<AdExtensionIdToEntityIdAssociation> associations, AssociationType associationType)
        {
            var request = new SetAdExtensionsAssociationsRequest
            {
                AccountId = accountId,
                AdExtensionIdToEntityIdAssociations = associations,
                AssociationType = associationType
            };

            await Service.CallAsync((s, r) => s.SetAdExtensionsAssociationsAsync(r), request);
        }

        // Removes the specified association from the respective campaigns or ad groups.

        private async Task DeleteAdExtensionsAssociationsAsync(long accountId, IList<AdExtensionIdToEntityIdAssociation> associations, AssociationType associationType)
        {
            var request = new DeleteAdExtensionsAssociationsRequest
            {
                AccountId = accountId,
                AdExtensionIdToEntityIdAssociations = associations,
                AssociationType = associationType
            };

            await Service.CallAsync((s, r) => s.DeleteAdExtensionsAssociationsAsync(r), request);
        }

        // Gets the specified ad extensions from the account's extension library.

        private async Task<IEnumerable<AdExtension>> GetAdExtensionsByIdsAsync(long accountId, IList<long> adExtensionIds, AdExtensionsTypeFilter adExtensionsTypeFilter)
        {
            var request = new GetAdExtensionsByIdsRequest
            {
                AccountId = accountId,
                AdExtensionIds = adExtensionIds,
                AdExtensionType = adExtensionsTypeFilter
            };

            return (await Service.CallAsync((s, r) => s.GetAdExtensionsByIdsAsync(r), request)).AdExtensions;
        }

        // Gets the reasons why the specified extension failed editorial when 
        // in the context of an associated campaign or ad group.

        private async Task<IList<AdExtensionEditorialReasonCollection>> GetAdExtensionsEditorialReasons(
            long accountId,
            IList<AdExtensionIdToEntityIdAssociation> associations,
            AssociationType associationType)
        {
            var request = new GetAdExtensionsEditorialReasonsRequest
            {
                AccountId = accountId,
                AdExtensionIdToEntityIdAssociations = associations,
                AssociationType = associationType
            };

            return (await Service.CallAsync(
                (s, r) => s.GetAdExtensionsEditorialReasonsAsync(r), request)).EditorialReasons;
        }

        /// <summary>
        /// Outputs the ad extensions with any editorial reasons
        /// </summary>
        /// <param name="adExtensions"></param>
        /// <param name="adExtensionEditorialReasonCollection"></param>
        protected void OutputAdExtensionsWithEditorialReasons(IEnumerable<AdExtension> adExtensions,
            IList<AdExtensionEditorialReasonCollection> adExtensionEditorialReasonCollection)
        {
            int index = 0;

            foreach (var extension in adExtensions)
            {
                if (extension == null || extension.Id == null)
                {
                    OutputStatusMessage("Extension is null or invalid.");
                }
                else
                {
                    var appAdExtension = extension as AppAdExtension;
                    if (appAdExtension != null)
                    {
                        OutputAppAdExtension(appAdExtension);
                    }
                    else
                    {
                        var callAdExtension = extension as CallAdExtension;
                        if (callAdExtension != null)
                        {
                            OutputCallAdExtension(callAdExtension);
                        }
                        else
                        {
                            var locationAdExtension = extension as LocationAdExtension;
                            if (locationAdExtension != null)
                            {
                                OutputLocationAdExtension(locationAdExtension);
                            }
                            else
                            {
                                var linksAdExtension = extension as SiteLinksAdExtension;
                                if (linksAdExtension != null)
                                {
                                    OutputSiteLinksAdExtension(linksAdExtension);
                                }
                                else
                                {
                                    OutputStatusMessage("Unknown extension type");
                                }
                            }
                        }
                    }

                    if (adExtensionEditorialReasonCollection != null
                        && adExtensionEditorialReasonCollection.Count > 0
                        && adExtensionEditorialReasonCollection[index] != null)
                    {
                        // Print any editorial rejection reasons for the corresponding extension. This example 
                        // assumes the same list index for adExtensions and adExtensionEditorialReasonCollection
                        // as defined above.

                        foreach (var adExtensionEditorialReason in adExtensionEditorialReasonCollection[index].Reasons)
                        {
                            if (adExtensionEditorialReason != null &&
                                adExtensionEditorialReason.PublisherCountries != null)
                            {
                                OutputStatusMessage("Editorial Rejection Location: " + adExtensionEditorialReason.Location);
                                OutputStatusMessage("Editorial Rejection PublisherCountries: ");
                                foreach (var publisherCountry in adExtensionEditorialReason.PublisherCountries)
                                {
                                    OutputStatusMessage("  " + publisherCountry);
                                }
                                OutputStatusMessage("Editorial Rejection ReasonCode: " + adExtensionEditorialReason.ReasonCode);
                                OutputStatusMessage("Editorial Rejection Term: " + adExtensionEditorialReason.Term);
                                OutputStatusMessage("\n");
                            }
                        }
                    }
                }
                index++;
            }
        }

        /// <summary>
        /// Outputs the AppAdExtension.
        /// </summary>
        protected void OutputAppAdExtension(AppAdExtension extension)
        {
            if (extension != null)
            {
                OutputStatusMessage(string.Format("AppPlatform: {0}", extension.AppPlatform));
                OutputStatusMessage(string.Format("AppStoreId: {0}", extension.AppStoreId));
                OutputStatusMessage(string.Format("DestinationUrl: {0}", extension.DestinationUrl));
                OutputStatusMessage(string.Format("DevicePreference: {0}", extension.DevicePreference));
                OutputStatusMessage(string.Format("DisplayText: {0}", extension.DisplayText));
                OutputStatusMessage("FinalMobileUrls: ");
                if (extension.FinalMobileUrls != null)
                {
                    foreach (var finalMobileUrl in extension.FinalMobileUrls)
                    {
                        OutputStatusMessage(string.Format("\t{0}", finalMobileUrl));
                    }
                }

                OutputStatusMessage("FinalUrls: ");
                if (extension.FinalUrls != null)
                {
                    foreach (var finalUrl in extension.FinalUrls)
                    {
                        OutputStatusMessage(string.Format("\t{0}", finalUrl));
                    }
                }
                OutputStatusMessage(string.Format("Id: {0}", extension.Id));
                OutputStatusMessage(string.Format("Status: {0}", extension.Status));
                OutputStatusMessage(string.Format("TrackingUrlTemplate: {0}", extension.TrackingUrlTemplate));
                OutputStatusMessage("UrlCustomParameters: ");
                if (extension.UrlCustomParameters != null && extension.UrlCustomParameters.Parameters != null)
                {
                    foreach (var customParameter in extension.UrlCustomParameters.Parameters)
                    {
                        OutputStatusMessage(string.Format("\tKey: {0}", customParameter.Key));
                        OutputStatusMessage(string.Format("\tValue: {0}", customParameter.Value));
                    }
                }
                OutputStatusMessage(string.Format("Version: {0}", extension.Version));
            }
        }

        /// <summary>
        /// Outputs the CallAdExtension.
        /// </summary>
        protected void OutputCallAdExtension(CallAdExtension extension)
        {
            if (extension != null)
            {
                OutputStatusMessage(string.Format("CountryCode: {0}", extension.CountryCode));
                OutputStatusMessage(string.Format("DevicePreference: {0}", extension.DevicePreference));
                OutputStatusMessage("ForwardCompatibilityMap: ");
                if (extension.ForwardCompatibilityMap != null)
                {
                    foreach (var pair in extension.ForwardCompatibilityMap)
                    {
                        OutputStatusMessage(string.Format("Key: {0}", pair.Key));
                        OutputStatusMessage(string.Format("Value: {0}", pair.Value));
                    }
                }
                OutputStatusMessage(string.Format("Id: {0}", extension.Id));
                OutputStatusMessage(string.Format("IsCallOnly: {0}", extension.IsCallOnly));
                OutputStatusMessage(string.Format("IsCallTrackingEnabled: {0}", extension.IsCallTrackingEnabled));
                OutputStatusMessage(string.Format("PhoneNumber: {0}", extension.PhoneNumber));
                OutputStatusMessage(string.Format("RequireTollFreeTrackingNumber: {0}", extension.RequireTollFreeTrackingNumber));
                OutputStatusMessage(string.Format("Status: {0}", extension.Status));
                OutputStatusMessage(string.Format("Version: {0}", extension.Version));
            }
        }

        /// <summary>
        /// Outputs the LocationAdExtension.
        /// </summary>
        protected void OutputLocationAdExtension(LocationAdExtension extension)
        {
            if (extension != null)
            {
                if (extension.Address != null)
                {
                    OutputStatusMessage(string.Format("CityName: {0}", extension.Address.CityName));
                    OutputStatusMessage(string.Format("CountryCode: {0}", extension.Address.CountryCode));
                    OutputStatusMessage(string.Format("PostalCode: {0}", extension.Address.PostalCode));
                    OutputStatusMessage(string.Format("ProvinceCode: {0}", extension.Address.ProvinceCode));
                    OutputStatusMessage(string.Format("ProvinceName: {0}", extension.Address.ProvinceName));
                    OutputStatusMessage(string.Format("StreetAddress: {0}", extension.Address.StreetAddress));
                    OutputStatusMessage(string.Format("StreetAddress2: {0}", extension.Address.StreetAddress2));
                }

                OutputStatusMessage(string.Format("CompanyName: {0}", extension.CompanyName));
                OutputStatusMessage("ForwardCompatibilityMap: ");
                if (extension.ForwardCompatibilityMap != null)
                {
                    foreach (var pair in extension.ForwardCompatibilityMap)
                    {
                        OutputStatusMessage(string.Format("Key: {0}", pair.Key));
                        OutputStatusMessage(string.Format("Value: {0}", pair.Value));
                    }
                }
                OutputStatusMessage(string.Format("GeoCodeStatus: {0}", extension.GeoCodeStatus));
                if (extension.GeoPoint != null)
                {
                    OutputStatusMessage("GeoPoint: ");
                    OutputStatusMessage(string.Format("LatitudeInMicroDegrees: {0}", extension.GeoPoint.LatitudeInMicroDegrees));
                    OutputStatusMessage(string.Format("LongitudeInMicroDegrees: {0}", extension.GeoPoint.LongitudeInMicroDegrees));
                }
                OutputStatusMessage(string.Format("IconMediaId: {0}", extension.IconMediaId));
                OutputStatusMessage(string.Format("Id: {0}", extension.Id));
                OutputStatusMessage(string.Format("ImageMediaId: {0}", extension.ImageMediaId));
                OutputStatusMessage(string.Format("PhoneNumber: {0}", extension.PhoneNumber));
                OutputStatusMessage(string.Format("Status: {0}", extension.Status));
                OutputStatusMessage(string.Format("Version: {0}", extension.Version));
            }
        }

        /// <summary>
        /// Outputs the SiteLinksAdExtension.
        /// </summary>
        protected void OutputSiteLinksAdExtension(SiteLinksAdExtension extension)
        {
            if (extension != null)
            {
                OutputStatusMessage("ForwardCompatibilityMap: ");
                if (extension.ForwardCompatibilityMap != null)
                {
                    foreach (var pair in extension.ForwardCompatibilityMap)
                    {
                        OutputStatusMessage(string.Format("Key: {0}", pair.Key));
                        OutputStatusMessage(string.Format("Value: {0}", pair.Value));
                    }
                }
                OutputStatusMessage(string.Format("Id: {0}", extension.Id));
                OutputStatusMessage(string.Format("Status: {0}", extension.Status));
                OutputStatusMessage(string.Format("Version: {0}", extension.Version));
                OutputSiteLinks(extension.SiteLinks);
            }
        }

        /// <summary>
        /// Outputs the list of SiteLink.
        /// </summary>
        protected void OutputSiteLinks(IList<SiteLink> siteLinks)
        {
            if (siteLinks != null)
            {
                foreach (var siteLink in siteLinks)
                {
                    OutputStatusMessage(string.Format("Description1: {0}", siteLink.Description1));
                    OutputStatusMessage(string.Format("Description2: {0}", siteLink.Description2));
                    OutputStatusMessage(string.Format("DestinationUrl: {0}", siteLink.DestinationUrl));
                    OutputStatusMessage(string.Format("DevicePreference: {0}", siteLink.DevicePreference));
                    OutputStatusMessage(string.Format("DisplayText: {0}", siteLink.DisplayText));
                }
            }
        }
    }
}

Getting Started Using C# with Bing Ads ServicesCampaign Setup and BasicsAd Extensions

Community Additions

ADD
Show: