逐步解說:C 中的 Bing 廣告 API 傳統型應用程式#
此範例 C# 控制台應用程式會透過您提供的認證提示使用者同意,然後取得已驗證使用者可以存取的帳戶。
您必須先註冊應用程式,並記下用戶端標識碼 (已註冊的應用程式識別碼) 。 如需註冊應用程式和授權碼授與流程的詳細資訊,請參閱 使用 OAuth 進行驗證。
您也需要生產 開發人員令牌。 您可以依照下面所述逐步建立範例,或從 GitHub 下載更多範例。
程式碼逐步解說
開啟 Visual Studio 開發環境。
透過檔案 -New ->>Project 建立新專案
在 [ 新增專案] 視窗的下拉式清單中選擇 [.NET Framework 4.8 ],然後按兩下 [控制台應用程式] (.NET [Framework) ] 範本。 將專案命名為 BingAdsConsoleApp ,然後按兩下 [ 確定]。
透過 NuGet 為 BingAdsConsoleApp 安裝 SDK。 如需相依性的詳細資訊,請 參閱安裝 SDK。 按兩下 [工具->NuGet 套件管理員 ->套件管理員主控台]。 在提示字元中,輸入下列命令,一次安裝一個套件: 和
Install-Package System.Configuration.ConfigurationManager
Install-Package Microsoft.BingAds.SDK
開啟 App.config 檔案,並以下列程式代碼區塊取代其內容。 編輯 BingAdsEnvironment 以從沙箱移至生產環境。 如果您的目標是生產環境,則必須將 4c0b021c-00c3-4508-838f-d3127e8167ff 取代為註冊生產應用程式時所布建的應用程式標識符,並將BBD37VB98取代為生產開發人員令牌。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" > <section name="BingAdsConsoleApp.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" /> </sectionGroup> </configSections> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.1" /> </startup> <appSettings> <!-- To use the production environment, set this value to "Production". --> <add key="BingAdsEnvironment" value="Sandbox"/> <add key="ClientSettingsProvider.ServiceUri" value=""/> </appSettings> <userSettings> <BingAdsConsoleApp.Properties.Settings> <setting name="DeveloperToken" serializeAs="String"> <value>BBD37VB98</value> </setting> <setting name="ClientId" serializeAs="String"> <value>4c0b021c-00c3-4508-838f-d3127e8167ff</value> </setting> </BingAdsConsoleApp.Properties.Settings> </userSettings> </configuration>
建立配置檔案。 在 BingAdsConsoleApp 的項目檢視中,以滑鼠右鍵按兩下 [ 屬性] ,然後按兩下 [ 開啟]。 按兩下 [ 設定],然後按下文字 [專案不包含預設配置檔案]。按兩下這裡建立一個。 系統會自動新增來自 app.config 的新值。
開啟Program.cs檔案,並以下列程式代碼區塊取代其內容。
using System; using System.Linq; using System.Configuration; using System.Net.Http; using System.ServiceModel; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.BingAds; using Microsoft.BingAds.V13.CustomerManagement; using BingAdsConsoleApp.Properties; using System.IO; namespace BingAdsConsoleApp { class Program { private static AuthorizationData _authorizationData; private static ServiceClient<ICustomerManagementService> _customerManagementService; private static string ClientState = "ClientStateGoesHere"; static void Main(string[] args) { try { Authentication authentication = AuthenticateWithOAuth(); // Most Bing Ads API service operations require account and customer ID. // This utiltiy operation sets the global authorization data instance // to the first account that the current authenticated user can access. SetAuthorizationDataAsync(authentication).Wait(); // You can extend the console app with the examples library at: // https://github.com/BingAds/BingAds-dotNet-SDK/tree/main/examples/BingAdsExamples } // Catch authentication exceptions catch (OAuthTokenRequestException ex) { OutputStatusMessage(string.Format("OAuthTokenRequestException Message:\n{0}", ex.Message)); if (ex.Details != null) { OutputStatusMessage(string.Format("OAuthTokenRequestException Details:\nError: {0}\nDescription: {1}", ex.Details.Error, ex.Details.Description)); } } // Catch Customer Management service exceptions catch (FaultException<AdApiFaultDetail> ex) { OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => { if ((error.Code == 105) || (error.Code == 106)) { return "Authorization data is missing or incomplete for the specified environment.\n" + "To run the examples switch users or contact support for help with the following error.\n"; } return string.Format("{0}: {1}", error.Code, error.Message); }))); OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } catch (FaultException<Microsoft.BingAds.V13.CustomerManagement.ApiFault> ex) { OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } catch (HttpRequestException ex) { OutputStatusMessage(ex.Message); } } /// <summary> /// Utility method for setting the customer and account identifiers within the global /// <see cref="_authorizationData"/> instance. /// </summary> /// <param name="authentication">The OAuth authentication credentials.</param> /// <returns></returns> private static async Task SetAuthorizationDataAsync(Authentication authentication) { _authorizationData = new AuthorizationData { Authentication = authentication, DeveloperToken = Settings.Default["DeveloperToken"].ToString() }; var apiEnvironment = ConfigurationManager.AppSettings["BingAdsEnvironment"] == ApiEnvironment.Sandbox.ToString() ? ApiEnvironment.Sandbox : ApiEnvironment.Production; _customerManagementService = new ServiceClient<ICustomerManagementService>( _authorizationData, apiEnvironment ); var getUserRequest = new GetUserRequest { UserId = null }; var getUserResponse = (await _customerManagementService.CallAsync((s, r) => s.GetUserAsync(r), getUserRequest)); var user = getUserResponse.User; var predicate = new Predicate { Field = "UserId", Operator = PredicateOperator.Equals, Value = user.Id.ToString() }; var paging = new Paging { Index = 0, Size = 10 }; var searchAccountsRequest = new SearchAccountsRequest { Ordering = null, PageInfo = paging, Predicates = new[] { predicate } }; var searchAccountsResponse = (await _customerManagementService.CallAsync((s, r) => s.SearchAccountsAsync(r), searchAccountsRequest)); var accounts = searchAccountsResponse.Accounts.ToArray(); if (accounts.Length <= 0) return; _authorizationData.AccountId = (long)accounts[0].Id; _authorizationData.CustomerId = (int)accounts[0].ParentCustomerId; OutputArrayOfAdvertiserAccount(accounts); return; } /// <summary> /// Authenticates the current user via OAuth. /// </summary> /// <returns>The OAuth authentication instance for a user.</returns> private static Authentication AuthenticateWithOAuth() { var apiEnvironment = ConfigurationManager.AppSettings["BingAdsEnvironment"] == ApiEnvironment.Sandbox.ToString() ? ApiEnvironment.Sandbox : ApiEnvironment.Production; var oAuthDesktopMobileAuthCodeGrant = new OAuthDesktopMobileAuthCodeGrant( Settings.Default["ClientId"].ToString(), apiEnvironment ); // It is recommended that you specify a non guessable 'state' request parameter to help prevent // cross site request forgery (CSRF). oAuthDesktopMobileAuthCodeGrant.State = ClientState; string refreshToken; // If you have previously securely stored a refresh token, try to use it. if (GetRefreshToken(out refreshToken)) { AuthorizeWithRefreshTokenAsync(oAuthDesktopMobileAuthCodeGrant, refreshToken).Wait(); } else { // You must request user consent at least once through a web browser control. Console.WriteLine(string.Format( "Open a new web browser and navigate to {0}\n\n" + "Grant consent in the web browser for the application to access " + "your advertising accounts, and then enter the response URI that includes " + "the authorization 'code' parameter: \n", oAuthDesktopMobileAuthCodeGrant.GetAuthorizationEndpoint()) ); // Request access and refresh tokens using the URI that you provided manually during program execution. var responseUri = new Uri(Console.ReadLine()); if (oAuthDesktopMobileAuthCodeGrant.State != ClientState) throw new HttpRequestException("The OAuth response state does not match the client request state."); oAuthDesktopMobileAuthCodeGrant.RequestAccessAndRefreshTokensAsync(responseUri).Wait(); SaveRefreshToken(oAuthDesktopMobileAuthCodeGrant.OAuthTokens.RefreshToken); } // It is important to save the most recent refresh token whenever new OAuth tokens are received. // You will want to subscribe to the NewOAuthTokensReceived event handler. // When calling Bing Ads API service operations with ServiceClient<TService>, BulkServiceManager, or ReportingServiceManager, // each instance will refresh your access token automatically if they detect the AuthenticationTokenExpired (109) error code. oAuthDesktopMobileAuthCodeGrant.NewOAuthTokensReceived += (sender, tokens) => SaveRefreshToken(tokens.NewRefreshToken); return oAuthDesktopMobileAuthCodeGrant; } /// <summary> /// Requests new access and refresh tokens given an existing refresh token. /// </summary> /// <param name="authentication">The OAuth authentication instance for a user.</param> /// <param name="refreshToken">The previous refresh token.</param> /// <returns></returns> private static Task<OAuthTokens> AuthorizeWithRefreshTokenAsync( OAuthDesktopMobileAuthCodeGrant authentication, string refreshToken) { return authentication.RequestAccessAndRefreshTokensAsync(refreshToken); } /// <summary> /// You should modify the example, and store the refresh token securely. /// </summary> /// <param name="newRefreshtoken">The refresh token to save.</param> private static void SaveRefreshToken(string newRefreshtoken) { if (newRefreshtoken != null) { using (StreamWriter outputFile = new StreamWriter( Environment.CurrentDirectory + @"\refreshtoken.txt", false)) { outputFile.WriteLine(newRefreshtoken); } } } /// <summary> /// Returns the prior refresh token if available. /// </summary> /// <param name="refreshToken"></param> /// <returns>The latest stored refresh token.</returns> private static bool GetRefreshToken(out string refreshToken) { var filePath = Environment.CurrentDirectory + @"\refreshtoken.txt"; if (!File.Exists(filePath)) { refreshToken = null; return false; } String fileContents; using (StreamReader sr = new StreamReader(filePath)) { fileContents = sr.ReadToEnd(); } if (string.IsNullOrEmpty(fileContents)) { refreshToken = null; return false; } try { refreshToken = fileContents; return true; } catch (FormatException) { refreshToken = null; return false; } } #region OutputHelpers /** * You can extend the console app with the example helpers at: * https://github.com/BingAds/BingAds-dotNet-SDK/tree/main/examples/BingAdsExamples **/ private static void OutputArrayOfAdvertiserAccount(IList<AdvertiserAccount> dataObjects) { if (null != dataObjects) { foreach (var dataObject in dataObjects) { OutputAdvertiserAccount(dataObject); OutputStatusMessage("\n"); } } } private static void OutputAdvertiserAccount(AdvertiserAccount dataObject) { if (null != dataObject) { OutputStatusMessage(string.Format("BillToCustomerId: {0}", dataObject.BillToCustomerId)); OutputStatusMessage(string.Format("CurrencyCode: {0}", dataObject.CurrencyCode)); OutputStatusMessage(string.Format("AccountFinancialStatus: {0}", dataObject.AccountFinancialStatus)); OutputStatusMessage(string.Format("Id: {0}", dataObject.Id)); OutputStatusMessage(string.Format("Language: {0}", dataObject.Language)); OutputStatusMessage(string.Format("LastModifiedByUserId: {0}", dataObject.LastModifiedByUserId)); OutputStatusMessage(string.Format("LastModifiedTime: {0}", dataObject.LastModifiedTime)); OutputStatusMessage(string.Format("Name: {0}", dataObject.Name)); OutputStatusMessage(string.Format("Number: {0}", dataObject.Number)); OutputStatusMessage(string.Format("ParentCustomerId: {0}", dataObject.ParentCustomerId)); OutputStatusMessage(string.Format("PaymentMethodId: {0}", dataObject.PaymentMethodId)); OutputStatusMessage(string.Format("PaymentMethodType: {0}", dataObject.PaymentMethodType)); OutputStatusMessage(string.Format("PrimaryUserId: {0}", dataObject.PrimaryUserId)); OutputStatusMessage(string.Format("AccountLifeCycleStatus: {0}", dataObject.AccountLifeCycleStatus)); OutputStatusMessage(string.Format("TimeStamp: {0}", dataObject.TimeStamp)); OutputStatusMessage(string.Format("TimeZone: {0}", dataObject.TimeZone)); OutputStatusMessage(string.Format("PauseReason: {0}", dataObject.PauseReason)); OutputArrayOfKeyValuePairOfstringstring(dataObject.ForwardCompatibilityMap); OutputArrayOfCustomerInfo(dataObject.LinkedAgencies); OutputStatusMessage(string.Format("SalesHouseCustomerId: {0}", dataObject.SalesHouseCustomerId)); OutputArrayOfKeyValuePairOfstringstring(dataObject.TaxInformation); OutputStatusMessage(string.Format("BackUpPaymentInstrumentId: {0}", dataObject.BackUpPaymentInstrumentId)); OutputStatusMessage(string.Format("BillingThresholdAmount: {0}", dataObject.BillingThresholdAmount)); OutputAddress(dataObject.BusinessAddress); OutputStatusMessage(string.Format("AutoTagType: {0}", dataObject.AutoTagType)); OutputStatusMessage(string.Format("SoldToPaymentInstrumentId: {0}", dataObject.SoldToPaymentInstrumentId)); } } private static void OutputAddress(Address dataObject) { if (null != dataObject) { OutputStatusMessage(string.Format("City: {0}", dataObject.City)); OutputStatusMessage(string.Format("CountryCode: {0}", dataObject.CountryCode)); OutputStatusMessage(string.Format("Id: {0}", dataObject.Id)); OutputStatusMessage(string.Format("Line1: {0}", dataObject.Line1)); OutputStatusMessage(string.Format("Line2: {0}", dataObject.Line2)); OutputStatusMessage(string.Format("Line3: {0}", dataObject.Line3)); OutputStatusMessage(string.Format("Line4: {0}", dataObject.Line4)); OutputStatusMessage(string.Format("PostalCode: {0}", dataObject.PostalCode)); OutputStatusMessage(string.Format("StateOrProvince: {0}", dataObject.StateOrProvince)); OutputStatusMessage(string.Format("TimeStamp: {0}", dataObject.TimeStamp)); OutputStatusMessage(string.Format("BusinessName: {0}", dataObject.BusinessName)); } } private static void OutputArrayOfKeyValuePairOfstringstring(IList<KeyValuePair<string, string>> dataObjects) { if (null != dataObjects) { foreach (var dataObject in dataObjects) { OutputKeyValuePairOfstringstring(dataObject); } } } private static void OutputKeyValuePairOfstringstring(KeyValuePair<string, string> dataObject) { if (null != dataObject.Key) { OutputStatusMessage(string.Format("key: {0}", dataObject.Key)); OutputStatusMessage(string.Format("value: {0}", dataObject.Value)); } } private static void OutputCustomerInfo(CustomerInfo dataObject) { if (null != dataObject) { OutputStatusMessage(string.Format("Id: {0}", dataObject.Id)); OutputStatusMessage(string.Format("Name: {0}", dataObject.Name)); } } private static void OutputArrayOfCustomerInfo(IList<CustomerInfo> dataObjects) { if (null != dataObjects) { foreach (var dataObject in dataObjects) { OutputCustomerInfo(dataObject); OutputStatusMessage("\n"); } } } private static void OutputStatusMessage(String msg) { Console.WriteLine(msg); } #endregion OutputHelpers } }
按兩下 [建置 ->建置 BingAdsConsoleApp],然後執行應用程式。 當您啟動應用程式時,預設會提示您在生產環境中驗證 Microsoft 帳戶認證。
設定沙箱
若要使用沙箱,請在專案根目錄 App.config檔的 appSettings> 節點內<,將 BingAdsEnvironment 金鑰設定為沙箱。
<add key="BingAdsEnvironment" value ="Sandbox"/>
您也可以個別設定每個 ServiceClient 的環境,如下所示。
_customerManagementService = new ServiceClient<ICustomerManagementService>(
_authorizationData,
ApiEnvironment.Sandbox
);
無論您是全域或個別設定 ServiceClient 環境,您也必須將 OAuth 環境設定為沙箱。
var oAuthDesktopMobileAuthCodeGrant = new OAuthDesktopMobileAuthCodeGrant(
ClientId,
ApiEnvironment.Sandbox
);