I'm trying to fetch BingAds data via SSIS to store in our accounting system. I've added a Service Reference to https://api.sandbox.bingads.microsoft.com/Api/Advertiser/v8/CampaignManagement/CampaignManagementService.svc?wsdl for testing.
I've copied the GetCampaigns code directly from http://msdn.microsoft.com/en-us/library/adcenter-campaign-management-csharp-samples-get-campaigns.aspx, and modified slightly, since this isn't a console application.
When I run my Script Component, I get the following message:
Message
Could not find default endpoint element that references contract
'BingAds.CampaignManagementService.ICampaignManagementService' in the ServiceModel
client configuration section. This might be because no configuration file was
found for your application, or because no endpoint element matching this contract
could be found in the client element.
My app.config looks like it should have everything that's needed. Am I missing something?
My app.config is below:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ICampaignManagementService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://api.sandbox.bingads.microsoft.com/Api/Advertiser/V8/CampaignManagement/CampaignManagementService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ICampaignManagementService"
contract="BingAds.CampaignManagementService.ICampaignManagementService"
name="BasicHttpBinding_ICampaignManagementService" />
</client>
</system.serviceModel>
</configuration>
And my script component code is below:
#region Namespaces
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.IO;
using System.Xml;
using System.Net;
// @TODO this should be something more sane; we'll get to that
using SC_356d75396bc04171b425bdd1a48dd7b6.BingAds.CampaignManagementService;
#endregion
namespace GetCampaignsByAccount
{
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
private static CampaignManagementServiceClient service = null;
// private static StringBuilder output_messages = new StringBuilder();
private static List<string> strings = new List<string>();
// Specify your credentials.
private static string m_password = "";
private static string m_username = "";
private static string m_token = "";
// Specify the advertiser's account ID and customer ID.
private static long m_accountId = null;
private static long m_customerId = null;
// Simple example that shows how to create a campaign.
static void Main()
{
Campaign[] campaigns = null;
try
{
CampaignManagementServiceClient service = new CampaignManagementServiceClient();
campaigns = GetCampaigns(m_customerId, m_accountId);
// Print information about the campaigns.
if (campaigns.Length > 0) {
AddMessage("Account {0} contains the following campaigns", m_accountId);
foreach (Campaign campaign in campaigns) {
AddMessage("Campaign: {0}", campaign.Name);
AddMessage("ID: {0}", campaign.Id);
// AddMessage("Status: {0}", campaign.Status);
AddMessage("Time zone: {0}", campaign.TimeZone);
// AddMessage("Budget type: {0}", campaign.BudgetType);
if (BudgetLimitType.MonthlyBudgetSpendUntilDepleted == campaign.BudgetType)
{
Console.WriteLine("Monthly budget: {0:C}", campaign.MonthlyBudget);
}
else
{
Console.WriteLine("Daily budget: {0:C}", campaign.DailyBudget);
}
Console.WriteLine();
}
}
else
{
AddMessage("Account {0} does not contain campaigns.", m_accountId);
}
service.Close();
}
catch (CommunicationException e)
{
AddMessage("{0}", "Communication Exception!");
AddMessage("{0}", e.Message);
AddMessage("{0}", e.StackTrace);
if (null != e.InnerException)
{
AddMessage("{0}", "Inner Exception!");
AddMessage("{0}", e.InnerException.Message);
AddMessage("{0}", e.InnerException.StackTrace);
}
if (service != null)
{
service.Abort();
}
}
catch (TimeoutException e)
{
AddMessage("{0}", "Timeout Exception!");
AddMessage("{0}", e.Message);
AddMessage("{0}", e.StackTrace);
if (service != null)
{
service.Abort();
}
}
catch (Exception e)
{
// Ignore fault exceptions that we already caught.
if (e.InnerException is FaultException)
{
;
}
else
{
AddMessage("{0}", "Other Exception!");
AddMessage("{0}", e.Message);
AddMessage("{0}", e.StackTrace);
}
if (service != null)
{
service.Abort();
}
}
}
private static void AddMessage(string format, string str)
{
string[] lines = str.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
foreach (string value in lines)
{
string longVal = String.Format(format, value);
strings.Add(longVal.Substring(0, Math.Min(longVal.Length, 8000)));
}
}
private static void AddMessage(string format, long str)
{
strings.Add(String.Format(format, str));
}
private static void AddMessage(string format, long? str)
{
strings.Add(String.Format(format, str));
}
static Campaign[] GetCampaigns(long customerId, long accountId)
{
GetCampaignsByAccountIdRequest request = new GetCampaignsByAccountIdRequest();
GetCampaignsByAccountIdResponse response = null;
// Set the header information.
request.CustomerId = customerId.ToString();
request.CustomerAccountId = accountId.ToString();
request.DeveloperToken = m_token;
request.UserName = m_username;
request.Password = m_password;
// Set the request information.
request.AccountId = accountId;
try
{
response = service.GetCampaignsByAccountId(request);
}
catch (FaultException<AdApiFaultDetail> fault)
{
// Log this fault.
strings.Add("GetCampaignsByAccountId failed with the following faults:\n");
foreach (AdApiError error in fault.Detail.Errors)
{
if (105 == error.Code)
{ // InvalidCredentials
Console.WriteLine("The specified credentials are not valid " +
"or the account is inactive.");
}
else
{
Console.WriteLine("Error code: {0} ({1})\nMessage: {2}\nDetail: {3}\n",
error.ErrorCode, error.Code, error.Message, error.Detail);
}
}
throw new Exception("", fault);
}
catch (FaultException<ApiFaultDetail> fault)
{
// Log this fault.
Console.WriteLine("GetCampaignsByAccountId failed with the following faults:\n");
foreach (OperationError error in fault.Detail.OperationErrors)
{
switch (error.Code)
{
case 106: // UserIsNotAuthorized
Console.WriteLine("The user is not authorized to call this operation.");
break;
case 1030: // CampaignServiceAccountIdHasToBeSpecified
Console.WriteLine("The CustomerAccountId header element " +
"cannot be null or empty.");
break;
case 1102: // CampaignServiceInvalidAccountId
Console.WriteLine("The account ID is not valid");
break;
default:
Console.WriteLine("Error code: {0} ({1})\nMessage: {2}\nDetail: {3}\n",
error.ErrorCode, error.Code, error.Message, error.Details);
break;
}
}
// This is not a batch operation, so there should be no batch errors.
foreach (BatchError error in fault.Detail.BatchErrors)
{
Console.WriteLine("Unable to add extension #{0}", error.Index);
Console.WriteLine("Error code: {0} ({1})\nMessage: {2}\nDetail: {3}\n",
error.ErrorCode, error.Code, error.Message, error.Details);
}
throw new Exception("", fault);
}
return response.Campaigns;
}
/// <summary>
/// This method is called once, before rows begin to be processed in the data flow.
///
/// You can remove this method if you don't need to do anything here.
/// </summary>
public override void PreExecute()
{
base.PreExecute();
}
/// <summary>
/// This method is called after all the rows have passed through this component.
///
/// You can delete this method if you don't need to do anything here.
/// </summary>
public override void PostExecute()
{
base.PostExecute();
}
public override void CreateNewOutputRows()
{
Main();
foreach (string value in strings)
{
MessagesBuffer.AddRow();
MessagesBuffer.Message = value;
}
}
}
}