Microsoft Windows
Introduction
This article introduces a method to load and execute SSIS packages in Microsoft
Windows with a demo WPF application.
Background
IT professionals who are familiar with SSIS packages will know that there are two ways
of running SSIS packages. When developing an SSIS package in Visual Studio, we can
run it in debugging mode. When we finish the development of an SSIS package, we can
install it in SQL Server and run it. We can run the SSIS package in SQL Server either as a
task or as a scheduled SQL job.
It is also very common that we do not have the source project in Visual Studio, or we do
not have a SQL Server to execute an existing SSIS package. In this case, it will be nice
that we can have a desktop application that allows us to load the package and run it.
If we take a look at the .NET namespace "Microsoft.SqlServer.Dts.Runtime"
implemented in "Microsoft.SQLServer.ManagedDTS.dll" in the .NET Framework, we will
find that Microsoft has provided all the tools to load and execute SSIS packages in our
own applications. This article is to introduce a method to execute SSIS packages in a
Windows application using the tools provided. "dtexe" is a good utility, but the
command line utility is not very easy to use.
This article is not intended to give a demo on how to create and use SSIS packages. If
you are not familiar with SSIS packages, this is a very good reference link.
The demo Visual Studio solution in this article is developed in Visual Studio 2008 and
SQL Server 2008.
One of the projects is a .NET Class Library "SSISWindowsLibrary" that wraps the
functions provided by the namespace "Microsoft.SqlServer.Dts.Runtime". This library is
used to load, execute, and report the execution status of the SSIS packages in the WPF
project "SSISWindowsLauncher". In order to test the WPF application
"SSISWindowsLauncher", I also developed a simple SSIS package "SamplePackage.dtsx"
in the Integration Service Project "SampleSSIS".
I will give some detailed explanations on these projects, starting with the Class Library
"SSISWindowsLibrary".
using System;
using System.Collections.Generic;
Copy Code
using System.Linq;
using System.Text;
using Microsoft.SqlServer.Dts.Runtime;
namespace SSISWindowsLibrary
{
public enum DTSPackageStatus
{
Empty, LoadFailed, Loaded
};
public class DTSPackage
{
private string _PkgLocation;
private DTSPackageStatus _Status;
private Package _Pkg;
private Microsoft.SqlServer.Dts.Runtime.Application _app;
public string PkgLocation
{
get { return _PkgLocation; }
}
public DTSPackageStatus PackageStatus
{
get { return _Status; }
}
public DTSPackage()
{
_PkgLocation = null;
_Status = DTSPackageStatus.Empty;
_Pkg = null;
_app = new Microsoft.SqlServer.Dts.Runtime.Application();
}
private void DisposePackage()
{
if (_Pkg != null)
{
_Pkg.Dispose();
_Pkg = null;
}
}
public void ClearPackage()
{
_PkgLocation = null;
_Status = DTSPackageStatus.Empty;
DisposePackage();
}
public void LoadPackage(string PkgLocation)
{
_PkgLocation = PkgLocation;
if (PkgLocation != null)
{
DisposePackage();
try
{
_Pkg = _app.LoadPackage(PkgLocation, null);
_Status = DTSPackageStatus.Loaded;
}
catch
{
_Status = DTSPackageStatus.LoadFailed;
}
}
}
public void SetPakageConnections(System.Collections.Hashtable ConnectionCollection)
{
if (_Status == DTSPackageStatus.Loaded)
{
Connections connections = _Pkg.Connections;
for (int Idex = 0; Idex < connections.Count; Idex++)
{
ConnectionManager connection = connections[Idex];
string ConName = connection.Name;
if (ConnectionCollection.Contains(ConName))
{
connection.ConnectionString =
ConnectionCollection[ConName].ToString();
}
}
}
}
public System.Collections.Hashtable GetPackageConnections()
{
System.Collections.Hashtable ConnectionCollection =
new System.Collections.Hashtable();
if (_Status == DTSPackageStatus.Loaded)
{
Connections connections = _Pkg.Connections;
for (int Idex = 0; Idex < connections.Count; Idex++)
{
ConnectionManager connection = connections[Idex];
string ConName = connection.Name;
string ConStr = connection.ConnectionString;
ConnectionCollection.Add(ConName, ConStr);
}
}
return ConnectionCollection;
}
public DTSExecResult Execute()
{
return _Pkg.Execute();
}
public DTSExecResult Execute(SSISEventListener Listerner)
{
To load an SSIS package, we can simply create an object of the class " DTSPackage" and
use the "LoadPackage" method to load the package by providing a path to the "dtsx"
file. To execute the package, simply call the method " Execute" .
The class "DTSPackage" also provides two methods "GetPackageConnections" and
"SetPakageConnections". These two methods can be used to view and change the
connection strings for the connections in the SSIS package after the package is loaded
into the application.
There are two ways of calling the "Execute" method. If you do not care about the details
about the package execution, call it without any parameter. If you want to know the
details, you can create an "SSISEventListerner" object and pass it to the "Execute"
method. When finishing the execution, the listener object can provide us the details of
the execution.
The "SSISEventListerner" class is implemented as follows:
Hide Shrink
using
using
using
using
using
System;
System.Collections.Generic;
System.Linq;
System.Text;
Microsoft.SqlServer.Dts.Runtime;
namespace SSISWindowsLibrary
{
public class SSISEventListener :
Microsoft.SqlServer.Dts.Runtime.DefaultEvents
{
private System.Data.DataTable _EventLogTable;
private int _EventCount;
public SSISEventListener()
{
_EventCount = 0;
_EventLogTable = new System.Data.DataTable();
_EventLogTable.Columns.Add("Status",
System.Type.GetType("System.Int16"));
_EventLogTable.Columns.Add("Event Sequence",
System.Type.GetType("System.Int16"));
_EventLogTable.Columns.Add("Time",
System.Type.GetType("System.DateTime"));
_EventLogTable.Columns.Add("SSIS Execution Status",
System.Type.GetType("System.String"));
}
public int EventCount
{
Copy Code
<Window x:Class="SSISWindowsLauncher.WinMain"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:kit="http://schemas.microsoft.com/wpf/2008/toolkit"
xmlns:WF="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
Background="#E0E5FF" BorderThickness="1" BorderBrush="AliceBlue"
Title="SSIS Package Windows Launcher" WindowState="Maximized"
FontFamily="Verdana" FontSize="12">
<Grid Margin="10, 10, 10, 10">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="155"/>
<RowDefinition Height="*"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Margin="0, 10, 0, 0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="155" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="155" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" x:Name="lblPackagePath"
Foreground="Blue" Cursor="Hand"
FontSize="14" HorizontalAlignment="Right"
MouseDown="lblPackagePath_MouseDown">lblPackagePath</Label>
<Button Grid.Column="2" x:Name="btnLocatePackage"
Click="btnLocatePackage_Click">Load SSIS Package</Button>
<Button Grid.Column="4" x:Name="btnClearPackage"
Click="btnClearPackage_Click">Clear Package</Button>
</Grid>
<WindowsFormsHost Grid.Row="1"
Name="WFHTBConnections" Margin="0, 15, 0, 0">
<WF:DataGridView x:Name="TBConnections"
BackgroundColor="White"
AutoSizeColumnsMode="AllCells"></WF:DataGridView>
</WindowsFormsHost>
Copy Code
<WindowsFormsHost Grid.Row="2"
Name="WFHTBExecutionLog" Margin="0, 15, 0, 0">
<WF:DataGridView x:Name="TBExecutionLog"
BackgroundColor="White" ReadOnly="True"
AutoSizeColumnsMode="AllCells"></WF:DataGridView>
</WindowsFormsHost>
<Grid Grid.Row="3" Margin="0, 10, 0, 0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="300" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="180" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="180" />
</Grid.ColumnDefinitions>
<Button Grid.Column="1" x:Name="btnLaunchSSIS"
Click="btnLaunchSSIS_Click">Execute SSIS Package</Button>
<Button Grid.Column="3" x:Name="btnClearExecutionLog"
Click="btnClearExecutionLog_Click">Clear SSIS Execution Log</Button>
<Button Grid.Column="5" x:Name="btnClose"
Click="btnClose_Click">Close</Button>
</Grid>
</Grid>
</Window>
using
using
using
using
using
using
using
using
using
using
using
using
using
using
using
using
System;
System.Collections.Generic;
System.Linq;
System.Text;
System.Windows;
System.Windows.Controls;
System.Windows.Data;
System.Windows.Documents;
System.Windows.Input;
System.Windows.Media;
System.Windows.Media.Imaging;
System.Windows.Navigation;
System.Windows.Shapes;
System.Data;
SSISWindowsLibrary;
Microsoft.SqlServer.Dts.Runtime;
namespace SSISWindowsLauncher
{
/// <summary>
/// Interaction logic for WinMain.xaml
/// </summary>
public partial class WinMain : Window
{
private DTSPackage Pkg;
public WinMain()
Copy Code
{
InitializeComponent();
TBConnections.ColumnHeadersHeight = 30;
TBConnections.ColumnHeadersDefaultCellStyle.BackColor =
System.Drawing.Color.SeaShell;
TBConnections.ColumnHeadersDefaultCellStyle.Font =
new System.Drawing.Font("Verdana", 8,
System.Drawing.FontStyle.Bold);
TBConnections.CellBeginEdit +=
new System.Windows.Forms.DataGridViewCellCancelEventHandler(
TBConnections_CellBeginEdit);
TBConnections.CellEndEdit +=
new System.Windows.Forms.DataGridViewCellEventHandler(
TBConnections_CellEndEdit);
TBExecutionLog.ColumnHeadersHeight = 30;
TBExecutionLog.ColumnHeadersDefaultCellStyle.BackColor =
System.Drawing.Color.SeaShell;
TBExecutionLog.DefaultCellStyle.WrapMode =
System.Windows.Forms.DataGridViewTriState.True;
TBExecutionLog.AutoSizeColumnsMode =
System.Windows.Forms.DataGridViewAutoSizeColumnsMode.DisplayedCells;
TBExecutionLog.ColumnHeadersDefaultCellStyle.Font =
new System.Drawing.Font("Verdana", 8, System.Drawing.FontStyle.Bold);
TBExecutionLog.RowsAdded +=
new System.Windows.Forms.DataGridViewRowsAddedEventHandler(
TBExecutionLog_RowsAdded);
this.WindowStyle = WindowStyle.ThreeDBorderWindow;
Pkg = new DTSPackage();
UpdatelblPackagePath();
}
private void TBConnections_CellBeginEdit(object sender,
System.Windows.Forms.DataGridViewCellCancelEventArgs e)
{
System.Windows.Forms.DataGridViewCell Cell =
TBConnections.Rows[e.RowIndex].Cells[e.ColumnIndex];
Cell.Style.Font = new System.Drawing.Font("Verdana", 8,
System.Drawing.FontStyle.Italic|System.Drawing.FontStyle.Bold);
}
private void TBConnections_CellEndEdit(object sender,
System.Windows.Forms.DataGridViewCellEventArgs e)
{
System.Windows.Forms.DataGridViewCell Cell =
TBConnections.Rows[e.RowIndex].Cells[e.ColumnIndex];
Cell.Style.Font = new System.Drawing.Font("Verdana", 8,
System.Drawing.FontStyle.Regular);
}
private void TBExecutionLog_RowsAdded(Object sender,
System.Windows.Forms.DataGridViewRowsAddedEventArgs e)
{
if (TBExecutionLog.DataSource == null)
{
return;
}
return;
}
PkgLocation = dlg.FileName;
try
{
Pkg.LoadPackage(PkgLocation);
}
catch (System.Exception EX)
{
MessageBox.Show("The is a problem to load the SSIS package,
please make sure that it is a valid SSIS package file - " +
System.DateTime.Now.ToString() + ".\n\n" + EX.ToString());
btnClearPackage_Click(null, null);
UpdatelblPackagePath();
return;
}
if (Pkg.PackageStatus != DTSPackageStatus.Loaded) {
MessageBox.Show("There is a problem to load the package.
Please make sure the SSIS package is valid.");
btnClearPackage_Click(null, null);
UpdatelblPackagePath();
}
System.Collections.Hashtable PackageConnections = Pkg.GetPackageConnections();
System.Data.DataTable PackageConnectionsTable = new System.Data.DataTable();
PackageConnectionsTable.Columns.Add("SSIS Connection Name",
System.Type.GetType("System.String"));
PackageConnectionsTable.Columns.Add("Connection String",
System.Type.GetType("System.String"));
foreach (System.Collections.DictionaryEntry DE in PackageConnections)
{
string[] RowData = { (string)DE.Key, (string)DE.Value };
PackageConnectionsTable.Rows.Add(RowData);
}
PackageConnectionsTable.Columns[0].ReadOnly = true;
System.Data.DataView PackageConnectionTableView =
PackageConnectionsTable.DefaultView;
PackageConnectionTableView.AllowDelete = false;
PackageConnectionTableView.AllowNew = false;
TBConnections.DataSource = PackageConnectionTableView;
TBExecutionLog.DataSource = null;
UpdatelblPackagePath();
}
private void btnClearPackage_Click(object sender, RoutedEventArgs e)
{
Pkg.ClearPackage();
UpdatelblPackagePath();
TBConnections.DataSource = null;
TBExecutionLog.DataSource = null;
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
private void lblPackagePath_MouseDown(object sender, MouseButtonEventArgs e)
{
btnLocatePackage_Click(null, null);
}
private void btnClearExecutionLog_Click(object sender, RoutedEventArgs e)
{
TBExecutionLog.DataSource = null;
}
}
}
INTO
INTO
INTO
INTO
[SSISExperiment]
[SSISExperiment]
[SSISExperiment]
[SSISExperiment]
VALUES(1,
VALUES(2,
VALUES(3,
VALUES(4,
'Name
'Name
'Name
'Name
1',
2',
3',
4',
GETDATE())
GETDATE())
GETDATE())
GETDATE())
Copy Code
The sample SSIS package will be transferring the data from [SSISExperiment] to
[SSISExperimentTarget]. The following picture shows the data flow mapping of the SSIS
package:
Click the "Open" button, we can then load the SSIS package.
After the SSIS package is successfully loaded, the application shows us the connection
strings for the connections used in the SSIS package. In our "SamplePackage.dtsx", we
have only one connection. If you click on the connection string text, you will find
that the application allows you to change the connection string. In this simple test, let
me not make any change to the connection string. But if you play with this WPF
application a little more, you may find some other nice features in supporting loading
and executing SSIS packages.
Click the "Execute SSIS Package" button; the application will start to execute the loaded
SSIS package. The application shows the status of some of the important steps during
the execution. In this case, the SSIS package is executed successfully.
Now we can go to SQL Server and take a look at the table [SSISExperimentTarget], and
the data is indeed transferred successfully.
Points of Interest
The article introduced a method to load and execute SSIS packages in a Microsoft
Windows application. The sample WPF application that comes with this article is no
where close to a commercial grade software application. But it has pretty much all the
basic functionalities to load and execute an SSIS package in Microsoft Windows. If you
want, you can use it as it is, or make any changes to better fit your needs.
If you want to compile and test this application yourself, and if you want to use
my sample SSIS package, you will need to have SQL Server and you will need to have
the required permission to it. In my case, I am the server administrator of my SQL
Server. You will need to run the SQL script that comes with this article before you run
the SSIS package, and you will need to change the server name and database name in
the connection "Experiment" in "SamplePackage.dtsx". If you have expertise with
database connection strings, you may be able to change the SQL Server name and the
database name after the SSIS package is loaded in the "SSISWindowsLauncher"
application.
In the WPF application, you may notice that I used two " WindowsFormsHost"
containers to insert two "DataGridView" controls designed for Windows Forms
applications into the WPF application. It is just a matter of personal preference, simply
because I like the font shown in the "good old days" controls. WPF applications will need
.NET Framework to run anyway, so mixing Windows Forms controls in
WPF applications should not be cause deployment and maintenance problems.
I tested many SSIS packages with this application, and I noticed that SSIS
packages do not do lazy evaluation. This means that all the execution steps will be
independently evaluated before the package execution starts. Although it is a safe
approach, it limits developers from creating more powerful SSIS packages.
Another thing to remind my readers is that you may have noticed that I can view
your entire connection string for all the connections in the SSIS packages including the
user name and the password. So it is a better idea to use integrated authentication than
SQL Server authentication, unless you can find a good way to encrypt your user name
and password.
The application that comes with this article definitely leaves a lot of room for
improvement, particularly the class "SSISEventListener". If you want more detailed SSIS
execution information and if you want the information to be real time, you can create
your own listener and use it appropriately.
By looking into the application that comes with this article, you will have a better
insight into the SSIS packages and better understanding of the SSIS "technology".