ssis 执行 依赖

介绍 (Introduction)

The SSIS Script Task is a very powerful component to use in a SSIS package, and most of the time you can achieve with it what you want. Still, I have faced a few situations where a Script Task was not the best solution. In those cases I made a .NET Console application and executed it from within a SSIS package.

SSIS脚本任务是一个非常强大的组件,可以在SSIS包中使用,大多数时候您都可以用它来实现所需的功能。 不过,我仍然遇到了脚本任务不是最佳解决方案的几种情况。 在那种情况下,我制作了一个.NET Console应用程序,并从SSIS包中执行了该应用程序。

Reasons you might want to do this also include:

您可能要这样做的原因还包括:

  • You want to use the functionality in multiple SSIS packages and do not want to copy (the code inside a) a Script Task over and over again. 您想要在多个SSIS包中使用该功能,并且不想一遍又一遍地复制脚本任务(a中的代码)。
  • Your C# application becomes more complex than a single script, and developing it outside the SSIS package allows you to create it with a better structure (tiers, namespaces, classes). 您的C#应用​​程序比单个脚本变得更加复杂,并且在SSIS包之外进行开发可以使您使用更好的结构(层,名称空间,类)来创建它。
  • You do not want to (or company policy does not allow you to) register an .NET assembly in the Global Assembly Cache of a server on which SQL Server/SSIS is installed. 您不想(或公司策略不允许您)在安装了SQL Server / SSIS的服务器的全局程序集缓存中注册.NET程序集。

故事的两面:控制台应用程序和SSIS包 (Both sides of the story: Console app and SSIS Package)

To demonstrate you how this works I have to tell you both sides of the story: first how to develop your .NET console application to accept command line parameters and to return feedback and errors, and then how to call this console application in a SSIS Package and intercept the return code and (error) messages.

为了向您演示这是如何工作的,我必须告诉您故事的两个方面:首先,如何开发.NET控制台应用程序以接受命令行参数,并返回反馈和错误,然后如何在SSIS包中调用此控制台应用程序。并拦截返回代码和(错误)消息。

方面A:开发.NET控制台应用程序 (Side A: develop the .NET Console application)

For developing the console application I used Visual Studio 2017 Community Edition.

为了开发控制台应用程序,我使用了Visual Studio 2017 Community Edition。

As this post is not about any specific application, I have made a generic example, in which the console application (which I have called “ExampleConsoleApp”, sorry for that, no inspiration for a more interesting name) accepts three required string parameters and one optional boolean parameter.

由于本文不涉及任何特定的应用程序,因此我举了一个通用示例,其中控制台应用程序(我称为“ ExampleConsoleApp”,很抱歉,没有启发一个更有趣的名称)接受了三个必需的字符串参数和一个可选的布尔参数。

If you want to rebuild the example, just follow the steps:

如果要重建示例,请按照下列步骤操作:

To create a new empty Console application in Visual Studio select File > New > Project from the menu. Then from the project templates, choose

要在Visual Studio中创建新的空控制台应用程序,请从菜单中选择“ 文件”>“新建”>“项目 ”。 然后从项目模板中选择

Installed > Templates > Visual C# > Windows Classic Desktop > Console App (.NET Framework)

已安装>模板> Visual C#> Windows经典桌面>控制台应用程序(.NET Framework)

when using Visual Studio 2017 or

使用Visual Studio 2017时

Installed > Templates > Visual C# > Windows > Classic Desktop > Console Application

已安装>模板> Visual C#> Windows>经典桌面>控制台应用程序

when using Visual Studio 2015.

使用Visual Studio 2015时。

I’ll walk you through the code for the application, which is underneath. I have added a method CheckArgs which checks if the application is called with command line parameters. If not, a help text is shown for 30 seconds, that describes which command line parameters are required and optional.

我将引导您完成下面的应用程序代码。 我添加了一个CheckArgs方法,该方法检查是否使用命令行参数调用了该应用程序。 如果不是,将显示30秒钟的帮助文本,其中描述了哪些命令行参数是必需的和可选的。

Otherwise the application continues by parsing the command line parameters in method ParseArgs. Furthermore, the inline comment should help you to understand the concept. In the console application replace the entire contents of Program.cs by this (please note that at the bottom of the article a link will be provided to download all the source code):

否则,应用程序将继续解析方法ParseArgs中的命令行参数。 此外,内联注释应有助于您理解概念。 在控制台应用程序中,用此替换Program.cs的全部内容(请注意,在本文的底部,将提供一个链接来下载所有源代码):


using System;
using System.Threading;namespace ExampleConsoleApp
{class Program{/// <summary>/// Main is changed from a void (without returnvalue) to a method returning an int/// </summary>/// <param name="args"></param>/// <returns></returns>static int Main(string[] args){if (!CheckArgs(args)){return -2;}try{string param1 = string.Empty;string param2 = string.Empty;string param3 = string.Empty;bool param4 = true;ParseArgs(args, out param1, out param2, out param3, out param4);// TODO Add your own application logic here.// For the demo only. You can remove it:Console.WriteLine("(.. For debug only .. let's see what we've got ..)");Console.WriteLine("===============================================");Console.WriteLine("The following parameter values have been provided:");Console.WriteLine("===============================================");Console.WriteLine(string.Format("param1: {0}", param1));Console.WriteLine(string.Format("param2: {0}", param2));Console.WriteLine(string.Format("param3: {0}", param3));Console.WriteLine(string.Format("param4: {0}", param4.ToString().ToLower()));Thread.Sleep(10000); // 10 seconds to read the output.// Force an error when param1 has a certain value.// This is for the demo only. You can remove it:if (param1 == "testerror"){int zero = 0;int i = 1 / zero;}// If the application has finished successfully, return 0return 0;}catch (Exception ex){// Write the error to the StandardError output.Console.Error.WriteLine(ex.ToString());// Optionally write the error also to the StandardOutput output.Console.WriteLine(ex.ToString());// Get the errorcode of the exception.// If it would be 0 (the code for success), just return -1. // Otherwise return the real error code.int errorCode = ex.HResult;return (errorCode == 0 ? -1: errorCode);}}/// <summary>/// Checks if the application is called with command line parameters./// If not a message is shown on the command line for 30 seconds./// A more detailed check of the command line arguments is done in private static void ParseArgs./// </summary>/// <param name="args"></param>/// <returns></returns>private static bool CheckArgs(string[] args){if (args.Length == 0){Console.WriteLine("(.. You have 30 seconds to read this help text ..)");Console.Error.WriteLine("===============================================");Console.Error.WriteLine("This application needs command line parameters.");Console.Error.WriteLine("===============================================");Console.Error.WriteLine("Required parameters:");Console.Error.WriteLine("-param1, followed by the value of parameter 1");Console.Error.WriteLine("-param2, followed by the value of parameter 2");Console.Error.WriteLine("-param3, followed by the value of parameter 3");Console.Error.WriteLine("Optional parameters:");Console.Error.WriteLine("-param4, followed by the value of parameter 4. If not value provided, the default value 'true' will be used.");Console.Error.WriteLine("===============================================");Console.Error.WriteLine("Example of use:");Console.Error.WriteLine("ExampleConsoleApp.exe -param1 Value 1 with space -param2 Value2WithoutSpace -param3 Value 3 with space again -param4 false");// Use Sleep, so that:// - if ran interactively, give time to read the message.// - if ran from SSIS Package, prevent that console application stays open and waits for user input (would be the case when using Console.ReadKey();)Thread.Sleep(30000);return false;}return true;}/// <summary>/// Parses the command line parameters. /// In a real console application you would give your parameters more /// meaningful names instead of numbering them as param1, param2, etcetera./// </summary>/// <param name="args"></param>/// <param name="param1">Output parameter with value for param1.</param>/// <param name="param2">Output parameter with value for param2.</param>/// <param name="param3">Output parameter with value for param3.</param>/// <param name="param4">Output parameter with value for param4.</param> private static void ParseArgs(string[] args, out string param1, out string param2, out string param3, out bool param4){// Set the parameter values to default values first.param1 = string.Empty;param2 = string.Empty;param3 = string.Empty;param4 = true;// In case a parameter value contains spaces, it is spread over multiple // elements in the args[] array. In this case we use lastArg to concatenate// these different parts of the value to a single value.string lastArg = string.Empty;// If the next parameter is not found, the value must be of lastArg.bool foundNext = false;// paramCount is used to check that all required parameter values are provided.int paramCount = 0;// Loop through the args[] array. for (int i = 0; i <= args.GetUpperBound(0); i++){foundNext = false;// Create an if statement for each parameter that is provided on the command line.if (args[i].ToLower() == "-param1"){i++;paramCount++;foundNext = true;lastArg = "-param1";// Check if there is a value, otherwise keep the default.if (i > args.GetUpperBound(0)) break;param1 = args[i];}if (args[i].ToLower() == "-param2"){i++;paramCount++;foundNext = true;lastArg = "-param2";// Check if there is a value, otherwise keep the default.if (i > args.GetUpperBound(0)) break;param2 = args[i];}if (args[i].ToLower() == "-param3"){i++;paramCount++;foundNext = true;lastArg = "-param3";if (i > args.GetUpperBound(0)) break;param3 = args[i];}if (args[i].ToLower() == "-param4"){i++;// Optional parameter, so do not count it! paramCount++;foundNext = true;lastArg = "-param4";// Check if there is a value, otherwise keep the default.if (i > args.GetUpperBound(0)) break;param4 = (args[i].ToLower() == "true" ? true : false);}if (!foundNext){// In case a parameter value contains spaces, it is spread over multiple elements in the args[] array.// In this case we use lastArg to concatenate these different parts of the value to a single value.switch (lastArg){case "-param1":param1 = string.Format("{0} {1}", param1, args[i]);break;case "-param2":param2 = string.Format("{0} {1}", param2, args[i]);break;case "-param3":param3 = string.Format("{0} {1}", param3, args[i]);break;// -param4 is not listed here because it is a boolean// so spaces in the value should not occur.default:break;}}}if (paramCount < 3){string message = string.Format("Invalid arguments provided: {0}", String.Join(" ", args));throw new ArgumentException(message);}}}
}

In Visual Studio select menu option Build > Build Solution or Rebuild Solution. Copy the ExampleConsoleApp.exe and ExampleConsoleApp.exe.config files from the bin subfolder to a folder of your choice. I used C:\Temp.

在Visual Studio中,选择菜单选项Build> Build SolutionRebuild Solution。 将bin子文件夹中的ExampleConsoleApp.exe和ExampleConsoleApp.exe.config文件复制到您选择的文件夹中。 我用的是C:\ Temp。

乙方:开发SSIS套件 (Side B: develop the SSIS Package)

In the SSIS Package we use an Execute Process Task to execute our example console application. There are a few different ways to handle the execution result (return code) of the console application, which I will show you in a minute.

在SSIS包中,我们使用执行过程任务来执行示例控制台应用程序。 有几种不同的方式来处理控制台应用程序的执行结果(返回代码),我将在稍后介绍给您。

But first, execute the following steps:

但首先,请执行以下步骤:

Step 1 – Add parameters

步骤1 –添加参数

Add a number of parameters to the package: ExecutableName, ExecutablePath, Param1, Param2, Param3 and Param4, as shown in the picture below. Optionally this can also be variables, when the values do not need to be configurable after the SSIS package is deployed.

向包中添加许多参数: ExecutableNameExecutablePathParam1Param2Param3Param4 ,如下图所示。 可选地,当在SSIS程序包部署之后不需要配置值时,它也可以是变量。

Step 2 – Add variables

步骤2 –添加变量

Add a number of variables to the package: ReturnCode, StdError and StdOutput, as shown in the picture below. These variables are needed to store the information- and error messages and execution result of the console application.

将许多变量添加到包中: ReturnCodeStdErrorStdOutput ,如下图所示。 这些变量是存储控制台应用程序的信息和错误消息以及执行结果所必需的。

Step 3 – Add an Execute Process Task to the Control Flow

步骤3 –将执行流程任务添加到控制流

Add a Execute Process Task and configure its properties as follows:

添加执行流程任务并按如下方式配置其属性:

Property Value
FailPackageOnFailure False
FailParentOnFailure False
Expressions – Arguments “-param1 ” + @[$Package::Param1] + ” -param2 ” + @[$Package::Param2] + ” -param3 ” + @[$Package::Param3] + ” -param4 ” + LOWER((DT_WSTR, 5)@[$Package::Param4])
Expressions – Executable @[$Package::ExecutablePath] + “\\”+ @[$Package::ExecutableName]
ExecValueVariable User::ReturnCode
StandardErrorVariable User::StdError
StandardOutputVariable User::StdOutput
SuccessValue 0
FailTaskIfReturnCodeIsNotSuccessValue True
属性
FailPackageOnFailure
FailParentOnFailure
表达式–参数 “ -param1” + @ [$ Package :: Param1] +” -param2” + @ [$ Package :: Param2] +” -param3” + @ [$ Package :: Param3] +” -param4” + LOWER(( DT_WSTR,5)@ [$ Package :: Param4])
表达式–可执行 @ [$ Package :: ExecutablePath] +“ \\” + @ [$ Package :: ExecutableName]
ExecValueVariable 用户:: ReturnCode
StandardErrorVariable 用户:: StdError
标准输出变量 用户:: StdOutput
成功价值 0
FailTask​​IfReturnCodeIsNotSuccessValue 真正

The final result should look as follows:

最终结果应如下所示:

Step 4 – Handle the console application return code and proceed with the package

步骤4 –处理控制台应用程序的返回码,然后继续处理软件包

Now you can use an Execute SQL Task or a Script Task to do something with the ReturnCode, StdError or StdOutput values. This is optional. If you do not intend to use the values of StdError or StdOutput, for instance for logging, no extra task is needed.

现在,您可以使用Execute SQL TaskScript TaskReturnCode,StdErrorStdOutput值执行某些操作 。 这是可选的。 如果您不打算将StdErrorStdOutput的值用于记录例如,则不需要额外的任务。

Handle the error – option A

处理错误–选项A

Add a Script Task.
Add the following variables to the ReadyOnlyVariables list:
User::ReturnCode,User::StdError,User::StdOutput

添加脚本任务。
将以下变量添加到ReadyOnlyVariables列表中:
用户:: ReturnCode,用户:: StdError,用户:: StdOutput

Then add this code to public void Main()

然后将此代码添加到public void Main()


string errorOutput = Dts.Variables["User::StdError"].Value.ToString();
string standardOutput = Dts.Variables["User::StdOutput"].Value.ToString();
int returnCode = int.Parse(Dts.Variables["User::ReturnCode"].Value.ToString());// Check for the returnCode is not strictly necessary because the returnCode will
// be not equal to 0. This is defensive programming, and the same script would also
// work when it is executed after successful execution of the console app.
if (returnCode == 0)
{Dts.TaskResult = (int)ScriptResults.Success;
}
else
{// Add code to do something with the values of errorOutput and optionally standardOutput, e.g. logging.Dts.TaskResult = (int)ScriptResults.Failure;
}

Handle the error – option B

处理错误–选项B

Add an Execute SQL Task.
Configure the Parameter mapping as shown in the picture below:

添加一个执行SQL任务。
如下图所示配置参数映射:

On the General pane, make sure SQLSourceType is set to Direct input.
Add a connection, for the demo it does not really matter to which database.
Edit the SQLStatement by pasting the code below:

在“ 常规”窗格上,确保将SQLSourceType设置为“ 直接输入”。
添加一个连接,对于演示来说,对哪个数据库并不重要。
通过粘贴以下代码来编辑SQLStatement


DECLARE @OutputCode INT = ?
DECLARE @StdError NVARCHAR(MAX) = ?
DECLARE @StdOutput NVARCHAR(MAX) = ?
DECLARE @ExecutionGuid uniqueidentifier = ?
DECLARE @SourceGuid uniqueidentifier = ?DECLARE @Event sysname = 'OnError'
DECLARE @Source nvarchar(1024) = 'ExecConsoleAppDemo_B'
DECLARE @StartTime datetime2(7) = GETUTCDATE()
DECLARE @EndTime datetime2(7) = GETUTCDATE()
DECLARE @MessageClass tinyint = 1
DECLARE @RetentionClass tinyint = 1
DECLARE @Message nvarchar(2048) -- Just a simple example of logging the return code and standard error output (using my plug and play logging solution):
IF @OutputCode != 0
BEGINSET @StdError = @StdError + N' (return code ' + CONVERT(NVARCHAR, @OutputCode) + N')' ;SELECT @Message = LEFT(@StdError, 2048);EXECUTE [logdb].[log].[spAddLogEntry] @Event,@Source,@SourceGuid,@ExecutionGuid,@StartTime,@EndTime,@MessageClass,@RetentionClass,@MessageRAISERROR(@StdError, 16, 1);
END

The end result should be similar to this:

最终结果应与此类似:

Finally the demo package should look as follows when a Script Task is used ..

最后,当使用脚本任务时,演示包应如下所示。

.. or as follows when a Execute SQL Task is used:

..或使用Execute SQL Task时如下:

我们还有时间进行一些演示。 (We still have time for a little demo ..)

I will just run the package with the Execute SQL Task, because it contains the code for logging, so we can check the error message later. As you might have noticed in the code snippets, if Param1 is given the value testerror, a divide by zero error will occur, as it is deliberately programmed in the console app.

我将仅使用Execute SQL Task运行该程序包,因为它包含用于记录日志的代码,因此我们可以稍后检查错误消息。 如您在代码段中可能已经注意到的那样,如果为Param1赋予了testerror值,则除以零的错误将发生,因为它是在控制台应用程序中故意编程的。

So let’s run the package with this parameter value and see the error occur!

因此,让我们使用此参数值运行包,看看会发生错误!

The expected error occurs ..

发生预期的错误..

… and yes, it is the error that occurred in the console application and which was added to the error output stream of the console application.

…是的,这是控制台应用程序中发生的错误,它已添加到控制台应用程序的错误输出流中。

结论/总结 (Conclusion / Wrap up)

In this blog post I explained:

在这篇博客中,我解释了:

  • Why it can sometimes be useful to execute a console application instead of using a Script Task in a SSIS package. 为什么有时执行控制台应用程序而不是使用SSIS包中的脚本任务有时有用。
  • How you can create your own C# console application that can be executed with command line parameters. 如何创建可以使用命令行参数执行的C#控制台应用程序。
  • How this console application can be executed from within a SSIS Package. 如何从SSIS包中执行此控制台应用程序。
  • How the Return Code, Standard Error and Standard Output streams can be captured in SSIS Variables. 如何在SSIS变量中捕获返回码,标准错误和标准输出流。
  • How these variables can be used in a Script Task or an Execute SQL Task. 在脚本任务或执行SQL任务中如何使用这些变量。

资料下载 (Downloads)

Download the source code of the examples here:

在此处下载示例的源代码:

  • Console Application 控制台应用
  • SSIS Packages SSIS软件包

网络资源 (Resources on the web)

  • Execute Process Task Editor (Process Page) on docs.microsoft.com 在docs.microsoft.com上执行流程任务编辑器(“流程页”)
  • Command-Line Arguments (C# Programming Guide) on MSDN MSDN上的命令行参数(C#编程指南)
  • A Plug and Play Logging Solution (blog post on hansmichiels.com) 即插即用日志记录解决方案(hansmichiels.com上的博客文章)
  • Related: SSIS and PowerShell – Execute process task (on SQLShack) 相关:SSIS和PowerShell –执行流程任务(在SQLShack上)

翻译自: https://www.sqlshack.com/executing-net-console-application-ssis/

ssis 执行 依赖

ssis 执行 依赖_从SSIS执行您自己的.NET控制台应用程序相关推荐

  1. ssis 表达式任务_在SSIS中执行SQL任务:SqlStatementSource表达式与可变源类型

    ssis 表达式任务 In this article, I will give an overview of Execute SQL Task in SSIS and I will try to il ...

  2. ssis 列转换_将SSIS包转换为Biml脚本

    ssis 列转换 In our previous article, Getting started with Biml, we have explained what Biml is, what ar ...

  3. 查询sql执行计划_使用SQL执行计划进行查询性能调整

    查询sql执行计划 In the previous articles of this series (see the index at bottom), we went through many as ...

  4. 页面 动态显示cmd执行结果_把代码执行演示嵌在你的PPT中

    "Talk is cheap, show me your code!" 当一个程序员在做技术分享的时候, 代码演示经常是不可或缺的一个环节.然而在你的演示PPT和代码运行之间切换是 ...

  5. shellexecute 执行完成_用ShellExecute执行cmd命令遇到的问题总结

    1.如果命令中的路径包含空格,要把路径去掉头尾用双引号包含起来. 例:strPath = ""D:\\\"te st\\\"test.exe:(用"\ ...

  6. 拷贝依赖_还不懂零拷贝(Zero-Copy)?怎么称得上高级程序员

    概述 考虑这样一种常用的情形:你需要将静态内容(类似图片.文件)展示给用户.那么这个情形就意味着你需要先将静态内容从磁盘中拷贝出来放到一个内存buf中,然后将这个buf通过socket传输给用户,进而 ...

  7. java 执行ssis包_在SSIS包中使用CHECKPOINT重新启动包执行

    java 执行ssis包 In the article, SQL Server CHECKPOINT, Lazy Writer, Eager Writer and Dirty Pages in SQL ...

  8. ssis 包部署_如何使用各种选项从SSIS目录执行已部署的程序包

    ssis 包部署 In my previous two articles on SQL Server integration Services (SSIS), Parameterizing Datab ...

  9. ssis什么情况下用到变量_了解SSIS内存使用情况

    ssis什么情况下用到变量 In this article, I am going to explain in detail about SSIS memory usage and how can w ...

最新文章

  1. plsq如何快捷整理代码_PLSQL Developer使用技巧整理(转)
  2. 车小米O2O保养平台搭建完毕
  3. Redis集群架构搭建详解
  4. 【2019暑假刷题笔记-图的存储和图的遍历】绪论(代码模板-总结自《算法笔记》)
  5. numpy添加元素_科研速递 | 花费15年众望所归!NumPy论文终登上Nature!
  6. CF662C Binary Table(FWT_XOR卷积)
  7. JavaFX自定义控件– Nest Thermostat第2部分
  8. leetcode201. 数字范围按位与
  9. 将来不当科学家,今天不必做科研?
  10. 黑客是否可以攻击被拔掉网线的电脑?
  11. ADO.NET 3.5 同SQL 2008的新的存储过程保存方式
  12. OLT忘记登陆密码如何修改
  13. 挑战程序设计竞赛——抽签Ⅱ
  14. 信息系统分析与设计相关
  15. android 设备管理和凭证,简述设备管理的涵义
  16. S7-1500PLC仿真
  17. [sig19]寒霜引擎中strand-based(基于线)的头发渲染
  18. AutoIt 快速入门指南
  19. DOS中SET命令的详细用法
  20. 最佳治理实践?一文读懂YFI运行机制

热门文章

  1. python冒号声明类型_Python 函数参数有冒号 声明后有- 箭头 返回值注释 参数类型注释...
  2. allow control allow origin_Origin绘图笔记(一)——如何高效绘制一个漂亮的数据图...
  3. 光储充一体化充电站_【储能项目】国家电网与浙江瓯江口新区共建光储充一体化充电站项目...
  4. VS2010上连接SQLite数据库
  5. [APIO / CTSC2007]数据备份 --- 贪心
  6. 跨server传输数据注意事项
  7. 2017-06-27
  8. 怎么快速搭建属于自己的博客
  9. Redis——学习之路三(初识redis config配置)
  10. 【Express】—get传递参数