Calling adCenter API Operations Asynchronously

Hello

Some of you may be aware of this already but I want to make sure that you know that you can call the CampaignManagement, Administration, and Reporting service operations asynchronously in C# and Visual Basic. For details on calling service operations asynchronously, see the WCF documentation: Synchronous and Asynchronous Operations, How to: Call WCF Service Operations Asynchronously, and Asynchronous Programming Design Patterns.

Asynchronous operations are typically used to perform tasks that might take a long time to complete, such as opening large files, connecting to remote computers, or querying a database. An asynchronous operation executes in a thread separate from the main application thread. When an application calls methods to perform an operation asynchronously, the application can continue executing while the asynchronous method performs its task. Basically, use asynchronous calls when your application can continue doing useful work while the method call runs.

If you use the svcutil.exe utility, include the /async and  /tcv:Version35 switches. If you use the Add Service Reference wizard in Visual Studio, click the Advanced… button and check the Generate asynchronous operations checkbox in the Service Reference Settings window (along with the Always generate message contracts checkbox).

You can use event handlers or delegates to receive notification of when the asynchronous call completes. Event handlers are easier to write but delegates offer more flexibility. If you need to pass context information to the callback, you should use delegates. For example, when printing the string that indicates that the group was added, it might be nice to identify the campaign to which the group was added. If you use an event handler, you would need to come up with some external mechanism for keeping track of which campaign goes with which async call result. However, with the delegate model, the context information (in this case, the campaign ID) is passed through to the callback.

I've included examples for both callback models.

The following is a simple example that shows how to call the AddAdGroups operation asynchronously using an event handler.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ServiceModel;
using AsyncExample.CampaignManagement;

namespace AsyncExample
{
    class Program
    {
        private static Exception asyncException = null;
        private static AutoResetEvent AsyncResultsDone = new AutoResetEvent(false);
        private static CampaignManagementServiceClient service = null;

        static void Main(string[] args)
        {
            if (args.Length != 5)
            {
                Console.WriteLine("usage:\nAsyncExample campaignid username password devtoken accountid");
                return;
            }

            try
            {
                service = new CampaignManagementServiceClient("BasicHttpBinding_ICampaignManagementService");
                AddAdGroupsToCampaign(Convert.ToInt64(args[0]), args[1], args[2], args[3], Convert.ToInt64(args[4]));
                service.Close();
            }
            catch (CommunicationException e)
            {
                Console.WriteLine(e.Message);

                if (service != null)
                {
                    service.Abort();
                }
            }
            catch (TimeoutException e)
            {
                Console.WriteLine(e.Message);

                if (service != null)
                {
                    service.Abort();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);

                if (service != null)
                {
                    service.Abort();
                }
            }
        }

        static void AddAdGroupsToCampaign(
            long campaignId,
            string username,
            string password,
            string devToken,
            long accountId)
        {
            AddAdGroupsRequest request = new AddAdGroupsRequest();
            request.CustomerAccountId = accountId.ToString();
            request.DeveloperToken = devToken;
            request.UserName = username;
            request.Password = password;

            AdGroup[] adGroups = new AdGroup[1];

            // Force batch errors by not setting the properties of
            // the ad group object.

            adGroups[0] = new AdGroup();
            //adGroups[0].Name = "Skis";
            //adGroups[0].AdDistribution = AdDistribution.Search;
            //adGroups[0].BiddingModel = BiddingModel.Keyword;
            //adGroups[0].PricingModel = PricingModel.Cpc;
            //adGroups[0].LanguageAndRegion = "EnglishUnitedStates";

            //Bid bid = new Bid();
            //bid.Amount = 10.25;
            //adGroups[0].ExactMatchBid = bid;

            //adGroups[0].StartDate = null;

            //Date endDate = new Date();
            //endDate.Day = 31;
            //endDate.Month = 3;
            //endDate.Year = 2010;
            //adGroups[0].EndDate = endDate;

            request.AdGroups = adGroups;
            request.CampaignId = campaignId;

            service.AddAdGroupsCompleted += new EventHandler<AddAdGroupsCompletedEventArgs>(AddAdGroupsCallback);
            service.AddAdGroupsAsync(request);

            // Blocks until the operation completes; released in AddAdGroupsCallback.

            AsyncResultsDone.WaitOne();

            if (asyncException != null)
            {
                throw (asyncException);
            }
        }

        static void AddAdGroupsCallback(object sender, AddAdGroupsCompletedEventArgs args)
        {
            // If you need the service object, cast sender to CampaignManagementServiceClient. For example,
            // CampaignManagementServiceClient service = (CampaignManagementServiceClient)sender;

            if (args.Error != null)
            {
                Console.WriteLine("The following error(s) occurred while performing the AddAdGroups operation.\n");

                try
                {
                    throw (args.Error);
                }
                catch (FaultException<ApiFaultDetail> fault)
                {
                    ApiFaultDetail detail = fault.Detail;

                    // Display the service operation errors.

                    foreach (OperationError error in detail.OperationErrors)
                    {
                        Console.WriteLine("Message: {0}\nError code: {1}\n", error.Message, error.ErrorCode);
                    }

                    // Display the service operation batch errors.

                    foreach (BatchError error in detail.BatchErrors)
                    {
                        Console.WriteLine("Message: {0}\nError code: {1}\n", error.Message, error.Code);
                    }
                }
                catch (FaultException<AdApiFaultDetail> fault)
                {
                    AdApiFaultDetail detail = fault.Detail;

                    // Display the generic API errors.

                    foreach (AdApiError error in detail.Errors)
                    {
                        Console.WriteLine("Message: {0}\nError code: {1}\n", error.Message, error.ErrorCode);
                    }
                }
                catch (Exception e)
                {
                    // This will likely be the CommunicationException or TimeoutException
                    // exception. Need to get this exception back to the calling thread to
                    // handle; using the asyncException member for this purpose. The asyncException
                    // member is checked in the calling thread and is thrown if set.

                    asyncException = e;
                }
            }
            else if (args.Cancelled)
            {
                Console.WriteLine("The AddAdGroups operation was canceled.");
            }
            else
            {
                AddAdGroupsResponse response = args.Result;

                foreach (long id in response.AdGroupIds)
                {
                    Console.WriteLine("AdGroup {0} was added", id);
                }
            }

            AsyncResultsDone.Set();
        }
    }
}

 

The following is a simple example that shows how to call the AddAdGroups operation asynchronously using a delegate.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ServiceModel;
using AsyncExample.CampaignManagement;

namespace AsyncExample
{
    class Program
    {
        private static AutoResetEvent AsyncResultsDone = new AutoResetEvent(false);
        private static CampaignManagementServiceClient service = null;

        static void Main(string[] args)
        {
            if (args.Length != 5)
            {
                Console.WriteLine("usage:\nAsyncExample campaignid username password devtoken accountid");
                return;
            }

            try
            {
                service = new CampaignManagementServiceClient("BasicHttpBinding_ICampaignManagementService");
                AddAdGroupsToCampaign(Convert.ToInt64(args[0]), args[1], args[2], args[3], Convert.ToInt64(args[4]));
                service.Close();
            }
            catch (CommunicationException e)
            {
                Console.WriteLine(e.Message);

                if (service != null)
                {
                    service.Abort();
                }
            }
            catch (TimeoutException e)
            {
                Console.WriteLine(e.Message);

                if (service != null)
                {
                    service.Abort();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);

                if (service != null)
                {
                    service.Abort();
                }
            }
        }

        // Packages the request object and calls the AddAdGroups operation
        // asynchronously.

        static void AddAdGroupsToCampaign(
            long campaignId,
            string username,
            string password,
            string devToken,
            long accountId)
        {
            AddAdGroupsRequest request = new AddAdGroupsRequest();
            request.CustomerAccountId = accountId.ToString();
            request.DeveloperToken = devToken;
            request.UserName = username;
            request.Password = password;

            AdGroup[] adGroups = new AdGroup[1];

            // Force batch errors by not setting the properties of
            // the ad group object.

            adGroups[0] = new AdGroup();
            //adGroups[0].Name = "Skis";
            //adGroups[0].AdDistribution = AdDistribution.Search;
            //adGroups[0].BiddingModel = BiddingModel.Keyword;
            //adGroups[0].PricingModel = PricingModel.Cpc;
            //adGroups[0].LanguageAndRegion = "EnglishUnitedStates";

            //Bid bid = new Bid();
            //bid.Amount = 10.25;
            //adGroups[0].ExactMatchBid = bid;

            //adGroups[0].StartDate = null;

            //Date endDate = new Date();
            //endDate.Day = 31;
            //endDate.Month = 3;
            //endDate.Year = 2010;
            //adGroups[0].EndDate = endDate;

            request.AdGroups = adGroups;
            request.CampaignId = campaignId;

            // Begin the asynchronous call. Use the RequestState object
            // to provide context for the call.

            RequestState state = new RequestState(service, campaignId);
            service.BeginAddAdGroups(request, new AsyncCallback(AddAdGroupsCallback), state);

            // Blocks until the operation completes; released in AddAdGroupsCallback.

            AsyncResultsDone.WaitOne();

            // If the call failed, throw any exception that the callback did not handle;
            // the callback handles the fault exceptions, so this is likely a communication
            // or timeout exception.

            if (state.UnhandledException != null)
            {
                throw (state.UnhandledException);
            }
        }

        // Defines the state object that gives context to the asynchronous call.

        class RequestState
        {
            object context = null;
            Exception unhandledException = null;
            CampaignManagementServiceClient service;

            // For this example, the context object is the campaign identifier
            // to which the add groups are being added.

            public RequestState(CampaignManagementServiceClient service, object context)
            {
                this.service = service;
                this.context = context;
            }

            public object Context
            {
                get { return context; }
            }

            // The exception that the callback did not handle.

            public Exception UnhandledException
            {
                get { return unhandledException; }
                set { this.unhandledException = value; }
            }

            // Completes the asynchronous call.

            public AddAdGroupsResponse GetResult(IAsyncResult result)
            {
                return service.EndAddAdGroups(result);
            }
        }

        // Implements the AsyncCallback Delegate. This is called when
        // the operation completes. The delegate processes the response.
        // The delegate handles any fault exceptions but lets the calling
        // thread handle any others.

        static void AddAdGroupsCallback(IAsyncResult result)
        {
            RequestState state = result.AsyncState as RequestState;

            try
            {
                long campaignId = (long)state.Context;
                AddAdGroupsResponse response = state.GetResult(result);

                foreach (long id in response.AdGroupIds)
                {
                    Console.WriteLine("AdGroup {0} was added to campaign {1}", id, campaignId);
                }
            }
            catch (FaultException<AdApiFaultDetail> fault)
            {
                AdApiFaultDetail detail = fault.Detail;

                Console.WriteLine("The following error(s) occurred while performing the AddAdGroups operation.\n");

                // Display the generic API errors.

                foreach (AdApiError error in detail.Errors)
                {
                    Console.WriteLine("Message: {0}\nError code: {1}\n", error.Message, error.ErrorCode);
                }
            }
            catch (FaultException<ApiFaultDetail> fault)
            {
                ApiFaultDetail detail = fault.Detail;

                Console.WriteLine("The following error(s) occurred while performing the AddAdGroups operation.\n");

                // Display the service operation errors.

                foreach (OperationError error in detail.OperationErrors)
                {
                    Console.WriteLine("Message: {0}\nError code: {1}\n", error.Message, error.ErrorCode);
                }

                // Display the service batch errors.

                foreach (BatchError error in detail.BatchErrors)
                {
                    Console.WriteLine("Message: {0}\nError code: {1}\n", error.Message, error.Code);
                }
            }
            catch (Exception e)
            {
                // Need to get this exception back to the calling thread to handle;
                // using the UnhandledException property of the state object for this
                // purpose. The UnhandledException property is checked in the calling
                // thread and is thrown if set.

                state.UnhandledException = e;
            }
            finally
            {
                // Release the wait in the calling thread.

                AsyncResultsDone.Set();
            }
        }
    }
}

 

Thanks and enjoy!