【问题标题】:SSIS With Script Component and Service References带有脚本组件和服务引用的 SSIS
【发布时间】:2013-02-20 00:41:09
【问题描述】:

我正在尝试通过 SSIS 获取 BingAds 数据以存储在我们的会计系统中。我已将服务引用添加到https://api.sandbox.bingads.microsoft.com/Api/Advertiser/v8/CampaignManagement/CampaignManagementService.svc?wsdl 以进行测试。

我直接从 http://msdn.microsoft.com/en-us/library/adcenter-campaign-management-csharp-samples-get-campaigns.aspx 复制了 GetCampaigns 代码,并稍作修改,因为这不是控制台应用程序。

当我运行我的脚本组件时,我收到以下消息:

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.

我的 app.config 看起来应该包含所需的一切。我错过了什么吗?

我的 app.config 如下:

<?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>

我的脚本组件代码如下:

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

        }
    }
}

【问题讨论】:

  • 如果您使用提供的代码,将其添加到 .NET 控制台应用程序中,它可以工作吗?您需要注释掉对MessagesBuffer 的引用,否则,我的心理分析表明它应该很好。也许也删除超类和覆盖。无论如何,这是我区分它是“坏代码”还是“奇怪的 SSIS”的常用方法
  • 格伦,你有没有让这个工作?如果是这样,您可以发布工作代码例如使用吗?谢谢
  • 您在 BingAds 服务参考中定义的 CampaignManagementServiceClient() 方法是否有多个允许您重载它的构造函数。在我的情况下,我将服务生成的命名空间从工作控制台应用程序复制并粘贴到我的 SSIS 组件脚本中。我的方法调用从 ServiceSoapClient service = new ServiceSoapClient() 到 ServiceSoapClient service = new ServiceSoapClient(binding, remoteAddress)。 binding 和 remoteAddress 参数是在添加服务引用时在控制台应用程序中创建的 app.config 文件中定义的对象。

标签: c# sql-server ssis


【解决方案1】:

对于那些使用 SSDT 2015 的用户,使用调试器时 .config 文件的文件位置发生了变化;现在可以在以下路径下找到它们:C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Microsoft\SSIS\140\Binn

【讨论】:

    【解决方案2】:

    .NET 在加载配置数据时查找的配置文件是实际运行的可执行文件的配置文件;将app.config 添加到您的 SSIS 脚本组件的项目中不会生成 SSIS 知道要查找的配置文件。根据您选择运行包的方式,它将寻找 BIDS、SQL Server 或 dtexec 的配置文件。

    在代码中构建端点并完全绕过配置文件会好得多。如果您的大多数配置选项都是默认值,那么它甚至没有那么复杂,因为您只需要设置更改的属性。

    这个堆栈溢出问题应该告诉你如何去做:

    WCF Configuration without a config file

    【讨论】:

    • 很好,它甚至没有记录涉及到配置文件
    • 我没有创建app.config。 Visual Studio 做到了。我会试试 WCF 配置选项。
    • VS 在你添加服务引用时创建一个 app.config;它没有注意到有问题的项目类型不能使用 app.config。
    • 您可以在 app.config 文件中定义的脚本中创建绑定和端点对象,并在进行服务调用时使用它们(如果服务调用方法有多个构造函数)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多