Google Ads API is returning to beta status. Please read our blog post for more details.

Working with Protobuf Types

Since Google Ads API uses Protobuf as its default payload format, it is important to understand a few Protobuf conventions and types when working with the Google Ads API.

Wrapper types

Most fields in the Google Ads API use wrapper classes (e.g. StringValue), rather than primitive value types (e.g. String). For example, the Campaign's id field is a LongValue, not a long. This is done because some fields have a meaningful difference between the default value and no value, which is enabled by wrapper classes. They exist on all fields in the API for consistency--you can expect each field to work the same way.

The .NET library maps the wrapper type to the corresponding native type when it is nullable (e.g. StringValue is mapped to string) and to the corresponding Nullable type when the native type is a ValueType (e.g. LongValue is mapped to long?).

Repeated types

Array fields are represented in Google Ads API as readonly RepeatedField. E.g. the Campaign 's url_custom_parameters field is a repeated field, so it is represented as a readonly RepeatedField<CustomParameter> in the .NET client library.

Since the array fields are readonly, you cannot use collection initializers to initialize them. Instead, you need to add or remove values after initializing the object. The RepeatedField implements IList<T> interface.

An example is given below.


Campaign campaign = new Campaign()
{
    ResourceName = ResourceNames.Campaign(customerId, campaignId),
    Status = CampaignStatus.Paused,
    // Error, won't work.
    // UrlCustomParameters = new CustomParameter[]
    // {
    //     new CustomParameter { Key = "season", Value = "christmas" },
    //     new CustomParameter { Key = "promocode", Value = "NY123" }
    // }
};

// Add values to UrlCustomParameters using AddRange method.
campaign.UrlCustomParameters.AddRange(new CustomParameter[]
{
    new CustomParameter { Key = "season", Value = "christmas" },
    new CustomParameter { Key = "promocode", Value = "NY123" }
});

OneOf types

Some fields in Google Ads APIs are marked as OneOf fields, meaning that the field can hold different types, but hold only one value at a given time. OneOf fields are similar to union type in C.

The .NET library implements OneOf fields by providing one property for each type of value that can be held in a OneOf field, and all the properties updating a shared class field.

For example, the Campaign's campaign_bidding_strategy is marked as a OneOf field. This class is implemented as follows (code simplified for brevity):

public sealed partial class Campaign : pb::IMessage<Campaign>
{
    object campaignBiddingStrategy_ = null;
    CampaignBiddingStrategyOneofCase campaignBiddingStrategyCase_;

    public ManualCpc ManualCpc
    {
        get
        {
            return campaignBiddingStrategyCase_ == CampaignBiddingStrategyOneofCase.ManualCpc ?
                (ManualCpc) campaignBiddingStrategy_ : null;
        }
        set
        {
            campaignBiddingStrategy_ = value;
            campaignBiddingStrategyCase_ = CampaignBiddingStrategyOneofCase.ManualCpc;
        }
    }

    public ManualCpm ManualCpm
    {
        get
        {
            return campaignBiddingStrategyCase_ == CampaignBiddingStrategyOneofCase.ManualCpm ?
                (ManualCpm) campaignBiddingStrategy_ : null;
        }
        set
        {
            campaignBiddingStrategy_ = value;
            campaignBiddingStrategyCase_ = CampaignBiddingStrategyOneofCase.ManualCpm;
        }
    }

    public CampaignBiddingStrategyOneofCase CampaignBiddingStrategyCase
    {
        get { return campaignBiddingStrategyCase_; }
    }
}

Since OneOf properties share storage, one assignment can overwrite a previous assignment, leading to subtle bugs. For example,

Campaign campaign = new Campaign()
{
    ManualCpc = new ManualCpc()
    {
        EnhancedCpcEnabled = true
    },
    ManualCpm = new ManualCpm()
    {

    }
};

In this case, campaign.ManualCpc is now null, since initializing the campaign.ManualCpm field overwrites the previous initialization for campaign.ManualCpc.