4

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;
            }

        }
    }
}
Glen Solsberry
  • 11,960
  • 15
  • 69
  • 94
  • If you take your supplied code, add it into a .NET Console app, does it work? You'd need to comment out the references to `MessagesBuffer` but otherwise, my mental parsing says it should be good. Maybe remove the superclass and the overrides too. At any rate, that's my usual approach for isolating whether it's "bad code" or "weird SSIS" – billinkc Mar 05 '13 at 14:59
  • Glen, did you ever get this to work? If so, can you post the working code for example use? Thanks – 007 Feb 26 '16 at 18:43
  • Did your CampaignManagementServiceClient() method defined within the BingAds service reference have multiple constructors that would allow you to overload it. In my case I copied and pasted the service generated namespace from a working console app to my SSIS component script. My method call went from ServiceSoapClient service = new ServiceSoapClient() to ServiceSoapClient service = new ServiceSoapClient(binding, remoteAddress). The binding and remoteAddress parameters are objects that are defined within the app.config file that was created in the console app when adding the service reference. – Lew Sep 06 '17 at 20:41

2 Answers2

3

The configuration file that .NET looks for when it loads configuration data is the one for the executable that's actually running; adding an app.config to your SSIS Script Component's project isn't going to produce a configuration file that SSIS knows to look for. Depending on how you opt to run your packages, it's going to be looking for the configuration file for BIDS, or SQL Server, or dtexec.

You will be much better off constructing your endpoints in code and bypassing the configuration file entirely. If most of your configuration options are defaults it's not even that complex, as you only need to set the properties that changed.

This Stack Overflow Question should show you how to do it:

WCF Configuration without a config file

Community
  • 1
  • 1
Michael Edenfield
  • 28,070
  • 4
  • 86
  • 117
  • Good catch, it didn't even register that config files were involved – billinkc Mar 05 '13 at 15:08
  • I didn't create the `app.config` though. Visual Studio did. I'll give the WCF Configuration option a try. – Glen Solsberry Mar 05 '13 at 15:41
  • 1
    VS creates an app.config any time you add a service reference; it doesn't pay attention to the fact that the project type in question can't use an app.config. – Michael Edenfield Mar 05 '13 at 16:04
  • You can create the binding & endpoint objects within your script that are defined in the app.config file and use those when making a service call (if the service call methods has multiple constructors). – Lew Sep 06 '17 at 20:45
0

For those using SSDT 2015, the file location for .config files has shifted when using the debugger; they can now be found under the following path: C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Microsoft\SSIS\140\Binn

dan
  • 1