private async Task<string> DownloadFileAsyncImpl(ReportingDownloadParameters parameters, CancellationToken cancellationToken)
        {
            using (var operation = await SubmitDownloadAsyncImpl(parameters.ReportRequest).ConfigureAwait(false))
            {
                await operation.TrackAsync(cancellationToken).ConfigureAwait(false);

                return await DownloadReportingFile(parameters.ResultFileDirectory, parameters.ResultFileName, parameters.OverwriteResultFile, operation).ConfigureAwait(false);
            }
        }
 /// <summary>
 /// Downloads the specified reporting entities to a local file. 
 /// </summary>
 /// <param name="parameters">Determines various download parameters, for example what entities to download and where the file should be downloaded.
 /// Please see <see cref="ReportingDownloadParameters"/> for more information about available parameters.</param>
 /// <param name="cancellationToken">Cancellation token that can be used to cancel the tracking of the reporting operation on the client. Doesn't cancel the actual reporting operation on the server.</param>
 /// <returns>A task that represents the asynchronous operation. The task result will be the local reporting file path.</returns>
 /// <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>  
 /// <exception cref="ReportingOperationCouldNotBeCompletedException">Thrown if the reporting operation has failed </exception>
 public Task<string> DownloadFileAsync(ReportingDownloadParameters parameters, CancellationToken cancellationToken)
 {
     return DownloadFileAsyncImpl(parameters, cancellationToken);
 }
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                ReportingService = new ReportingServiceManager(authorizationData);
                ReportingService.StatusPollIntervalInMilliseconds = 5000;
                
                // You can submit one of the example reports, or build your own.
 
                var reportRequest = GetCampaignPerformanceReportRequest(authorizationData.AccountId);
                //var reportRequest = GetKeywordPerformanceReportRequest(authorizationData.AccountId);
                //var reportRequest = GetProductDimensionPerformanceReportRequest(authorizationData.AccountId);
                //var reportRequest = GetProductPartitionPerformanceReportRequest(authorizationData.AccountId);

                var reportingDownloadParameters = new ReportingDownloadParameters
                {
                    ReportRequest = reportRequest,
                    ResultFileDirectory = FileDirectory,
                    ResultFileName = ResultFileName,
                    OverwriteResultFile = true,
                };

                // Option A - Background Completion with ReportingServiceManager
                // You can submit a download or upload request and the ReportingServiceManager will automatically 
                // return results. The ReportingServiceManager abstracts the details of checking for result file 
                // completion, and you don't have to write any code for results polling.

                OutputStatusMessage("Awaiting Background Completion . . .");
                await BackgroundCompletion(reportingDownloadParameters);

                // Option B - Submit and Download with ReportingServiceManager
                // Submit the download request and then use the ReportingDownloadOperation result to 
                // track status yourself using GetStatusAsync.

                OutputStatusMessage("Awaiting Submit and Download . . .");
                await SubmitAndDownload(reportRequest);

                // Option C - Download Results with ReportingServiceManager
                // If for any reason you have to resume from a previous application state, 
                // you can use an existing download request identifier and use it 
                // to download the result file. Use TrackAsync to indicate that the application 
                // should wait to ensure that the download status is completed.

                // For example you might have previously retrieved a request ID using SubmitDownloadAsync.
                var reportingDownloadOperation = await ReportingService.SubmitDownloadAsync(reportRequest);
                var requestId = reportingDownloadOperation.RequestId;

                // Given the request ID above, you can resume the workflow and download the report.
                // The report request identifier is valid for two days. 
                // If you do not download the report within two days, you must request the report again.
                OutputStatusMessage("Awaiting Download Results . . .");
                await DownloadResults(requestId, authorizationData);

            }
            // 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 Reporting service exceptions
            catch (FaultException<Microsoft.BingAds.Reporting.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(String.Join("; ", ex.Detail.Errors.Select(error => String.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.Reporting.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 (ReportingOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the reporting operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (ReportingOperationCouldNotBeCompletedException ex)
            {
                OutputStatusMessage(String.Format("ReportingOperationCouldNotBeCompletedException Message: {0}", ex.Message));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
        }
 /// <summary>
 /// Downloads the specified reporting entities to a local file. 
 /// </summary>
 /// <param name="parameters">Determines various download parameters, for example what entities to download and where the file should be downloaded.
 /// Please see <see cref="ReportingDownloadParameters"/> for more information about available parameters.</param>
 /// <returns>A task that represents the asynchronous operation. The task result will be the local reporting file path.</returns>
 /// <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>  
 /// <exception cref="ReportingOperationCouldNotBeCompletedException">Thrown if the reporting operation has failed </exception>
 public Task<string> DownloadFileAsync(ReportingDownloadParameters parameters)
 {
     return DownloadFileAsync(parameters, CancellationToken.None);
 }
        /// <summary>
        /// You can submit a download or upload request and the ReportingServiceManager will automatically
        /// return results. The ReportingServiceManager abstracts the details of checking for result file
        /// completion, and you don't have to write any code for results polling.
        /// </summary>
        /// <param name="reportingDownloadParameters"></param>
        private async Task BackgroundCompletion(ReportingDownloadParameters reportingDownloadParameters)
        {
            // You may optionally cancel the download after a specified time interval. 
            // Pass this object to the DownloadFileAsync operation or specify CancellationToken.None. 
            var tokenSource = new CancellationTokenSource();
            tokenSource.CancelAfter(36000000);

            var resultFilePath = await ReportingService.DownloadFileAsync(reportingDownloadParameters, tokenSource.Token);
            OutputStatusMessage(String.Format("Download result file: {0}\n", resultFilePath));
        }