Example #1
0
        /// <summary>
        /// Calls the Bing Ads service and returns the response of the corresponding <paramref name="method"/> of the Bing Ads service.
        /// </summary>
        /// <typeparam name="TRequest">The type of the Bing Ads service request message.</typeparam>
        /// <typeparam name="TResponse">The type of the Bing Ads service response message.</typeparam>
        /// <param name="method">A delegate representing the Bing Ads service operation that should be called.</param>
        /// <param name="request">The request message object for the operation.</param>
        /// <returns>A task that represents the asynchronous operation. The task result will be the Bing Ads service response.</returns>
        /// <remarks>
        /// <para>
        /// The header elements that the method sets will differ depending on the type of authentication specified in
        /// <see cref="AuthorizationData"/> and the requirements of the service. For example if you use one of the OAuth classes,
        /// the AuthenticationToken will be set by this method, whereas the UserName and Password headers will remain empty.
        /// Some services such as Customer Management do not accept CustomerId and CustomerAccountId headers,
        /// so they will be ignored if you specified them in the <see cref="AuthorizationData"/> object.
        /// </para>
        /// <para>
        /// If you are using one of the OAuth classes for authentication and the access token has expired
        /// (error 109 is returned from the API), this method will try to refresh
        /// it using the current refresh token and retry the request with the new access token.
        /// </para>
        /// </remarks>
        /// <exception cref="FaultException{TDetail}">Thrown if a fault is returned from the Bing Ads service.</exception>
        /// <exception cref="OAuthTokenRequestException">Thrown if tokens can't be refreshed due to an error received from the Microsoft Account authorization server.</exception>
        public async Task <TResponse> CallAsync <TRequest, TResponse>(
            Func <TService, TRequest, Task <TResponse> > method, TRequest request)
            where TRequest : class
        {
            ValidateObjectStateAndParameters(method, request);

            await RequestAccessTokenIfNeeded().ConfigureAwait(false);

            _authorizationData.Authentication.SetAuthenticationFieldsOnApiRequestObject(request);

            SetCommonRequestFieldsFromUserData(request);

            var client = _serviceClientFactory.CreateServiceFromFactory(_channelFactory);

            var needToRefreshToken = false;

            do
            {
                if (needToRefreshToken)
                {
                    await RefreshAccessToken().ConfigureAwait(false);

                    _authorizationData.Authentication.SetAuthenticationFieldsOnApiRequestObject(request);
                }

                try
                {
                    var response = await method(client, request).ConfigureAwait(false);

                    return(response);
                }
                catch (FaultException ex)
                {
                    // If needToRefreshToken == true, it means one token refresh has alreay been attempted, and we shouldn't do it again
                    if (needToRefreshToken == false && RefreshOAuthTokensAutomatically && IsExpiredTokenException(ex))
                    {
                        needToRefreshToken = true;
                    }
                    else
                    {
                        ((IClientChannel)client).Abort();

                        throw;
                    }
                }
                catch (CommunicationException)
                {
                    ((IClientChannel)client).Abort();

                    throw;
                }
                catch (TimeoutException)
                {
                    ((IClientChannel)client).Abort();

                    throw;
                }
                catch (Exception)
                {
                    ((IClientChannel)client).Abort();

                    throw;
                }
            } while (true);
        }