Case
I want to use the
WMI Event Watcher Task to watch for new files in SSIS, but it doesn't allow me to watch subfolders and after catching an event it continues with the next task, but meanwhile it doesn't watch for new files until in starts again. Is there an alternative?
|
WMI Event Watcher Task |
Solution
An alternative could be to create a Windows Service that does the watching part and then executes a package when a new file arrives. For this example I used the full version of Visual Studio 2010 (SSDT BI is not enough). The example is in C#, but you can easily
convert that to VB.NET.
1) Windows Service Project
Start Visual Studio and create a new Windows Service Project. I used the 4.0 framework since I want to execute SSIS 2012 packages. For 2008 you can use 3.5.
|
Windows Service 4.0 C# |
2) App.Config
To avoid hardcoded connection strings, paths and filters, we first have to add an Application Configuration File (App.config). Right Click the project in the solution explorer, choose Add, New Item... and then Application Configuration File. After adding the app.config we need to edit it. You can copy the XML below to start with and add extra parameters at the end. Make sure the values are correct.
|
app.config |
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="WatcherPath" value="d:\MySourceFiles"/>
<add key="WatcherFilter" value="*.csv"/>
<add key="SqlConnectionString" value="Data Source=.\SQL2012;Initial Catalog=master;Integrated Security=SSPI;"/>
<add key="Catalog" value="SSISDB"/>
<add key="Folder" value="MyFolder"/>
<add key="Project" value="MyProject"/>
<add key="Package" value="MyPackage.dtsx"/>
<add key="LogFile" value="d:\FileWatcherForSSIS\log.txt"/>
</appSettings>
</configuration>
|
MyCatalogStructure |
3) Add References
Right click references in the Solution Explorer and choose Add Reference... For the configuration part we need to add two extra references that can be found in the .NET tab:
- System.Configuration.dll
- System.Configuration.Install.dll
|
Add References |
For executing the SSIS packages we need four extra references that can be found in the GAC (MSIL) folder. The exact place could vary, but here are mine for SSIS 2012. Use the browse tab in the Add Reference Window to add them.
C:\Windows\assembly\GAC_MSIL\Microsoft.SqlServer.ConnectionInfo\11.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.ConnectionInfo.dll
C:\Windows\assembly\GAC_MSIL\Microsoft.SqlServer.Management.Sdk.Sfc\11.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.Management.Sdk.Sfc.dll
C:\Windows\assembly\GAC_MSIL\Microsoft.SqlServer.Smo\11.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.Smo.dll
C:\Windows\assembly\GAC_MSIL\Microsoft.SqlServer.Management.IntegrationServices\11.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.Management.IntegrationServices.dll
4) Services1.cs
Now open the source code of Services1.cs to add the actual Windows Services code. In the grey designer surface press F7 or click on the link to switch to code view. Copy the code below. If you don't want to use the Project Deployment Model then you must slightly change the
code in the watcher_Created method.
// C# code
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel; // Added
using System.ComponentModel;
using System.Configuration; // Added
using System.Data;
using System.Data.SqlClient; // Added
using System.Diagnostics;
using System.IO; // Added
using System.Linq;
using System.ServiceProcess;
using System.Text;
using Microsoft.SqlServer.Management.IntegrationServices; // Added
namespace FileWatcherForSSIS
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
/// <summary>
/// Method that executes when the services starts
/// </summary>
/// <param name="args"></param>
protected override void OnStart(string[] args)
{
// Create FileSystemWatcher dynamically instead of via the designer
FileSystemWatcher watcher = new FileSystemWatcher();
// Determine the folder you are watching
watcher.Path = ConfigurationManager.AppSettings["WatcherPath"];
// Determine for which files to watch
watcher.Filter = ConfigurationManager.AppSettings["WatcherFilter"];
// Determine whether you also want to watch subfolders
watcher.IncludeSubdirectories = true;
// Determine for which changes to watch (multiple notify
// filters should be seperated by a pipeline |
watcher.EnableRaisingEvents = true;
//watcher.NotifyFilter = NotifyFilters.CreationTime;
// Determine what to do for which events
watcher.Created += new FileSystemEventHandler(watcher_Created);
// Log start of service
logText("FileWatcher started watching " + watcher.Path);
}
/// <summary>
/// Method that executes when the services stops
/// </summary>
protected override void OnStop()
{
// Log start of service
logText("FileWatcher stopped watching ");
}
// Define the event handlers.
private static void watcher_Created(object sender, FileSystemEventArgs e)
{
// Log start of service
logText("FileWatcher catched " + e.FullPath);
// Connection to the database server where the packages are located
using (SqlConnection ssisConnection = new SqlConnection(ConfigurationManager.AppSettings["SqlConnectionString"]))
{
try
{
// SSIS server object with sql connection
IntegrationServices ssisServer = new IntegrationServices(ssisConnection);
// Get values from app.config
string catalog = ConfigurationManager.AppSettings["Catalog"];
string folder = ConfigurationManager.AppSettings["Folder"];
string project = ConfigurationManager.AppSettings["Project"];
string package = ConfigurationManager.AppSettings["Package"];
// The reference to the package which you want to execute
PackageInfo ssisPackage = ssisServer.Catalogs[catalog].Folders[folder].Projects[project].Packages[package];
// Create collection of parameters
Collection<PackageInfo.ExecutionValueParameterSet> executionParameter = new Collection<PackageInfo.ExecutionValueParameterSet>();
// Add a package parameter
executionParameter.Add(new PackageInfo.ExecutionValueParameterSet { ObjectType = 30, ParameterName = "MyFilePathParameter", ParameterValue = e.FullPath });
// Add a logging level parameter: 1=basic, 2=performance
executionParameter.Add(new PackageInfo.ExecutionValueParameterSet { ObjectType = 50, ParameterName = "LOGGING_LEVEL", ParameterValue = 1 });
// Execute package asynchronized and get
// the identifier of the execution
long executionIdentifier = ssisPackage.Execute(false, null, executionParameter);
// Prevent 30 second time-out by getting the execution
// by its ID and then wait until it's completed
ExecutionOperation executionOperation = ssisServer.Catalogs[catalog].Executions[executionIdentifier];
// Wait while package is busy
while (!(executionOperation.Completed))
{
// Refresh and wait 5 seconds before retesting
executionOperation.Refresh();
System.Threading.Thread.Sleep(5000);
}
// Log package completion
logText("Package completed " + package);
}
catch (Exception ex)
{
logText("FileWatcher error " + ex.Message);
}
}
}
/// <summary>
/// Write message to log
/// </summary>
/// <param name="logText">the log message</param>
private static void logText(string logText)
{
// Simple log version. You can replace it by for example an eventlog writer
using (FileStream fs = new FileStream(ConfigurationManager.AppSettings["LogFile"], FileMode.Append, FileAccess.Write))
using (StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine(DateTime.Now.ToString() + " - " + logText);
}
}
}
}
5) Installer.cs
To make the Windows Services installable we need to add an Installer Class by right clicking the Solution Explorer and choose Add, New Item..
|
Installer.cs |
6) Add Service(Process)Installer
Next you can drag ServiceInstaller and ServiceProcessInstaller from the toolbox to the designer surface of install.cs. If they are not available in the toolbox then you need to add them manually by right clicking the toolbox and choose Choose Items... (just like in SSIS 2008 when adding Third Party tasks).
|
Service(Process)Installer |
7) Edit Service(Process)Installer
In the properties of serviceInstaller1 you can set values for properties like ServiceName, DisplayName and the Description of the service.
|
Service Properties |
8) Building & Deploying
Now build the project in release mode (via build menu or Ctrl + Shft + B) and go to the bin release folder of your project. Copy these files to a suitable location for the service.
|
Bin Release Folder |
9) InstallUtil
Now open the Visual Studio 201X command prompt as Administrator (otherwise you don't have rights to add a new service). In the command prompt go to the folder where the service is located.
Then enter the following command:
installutil FileWatcherForSSIS.exe. During installation it will ask for the account that runs the service. The user must be able to read the folder and to execute the package (just like the user in a SQL Server Agent jobstep). For your production server without Visual Studio (and without
installutil.exe) you need to
create a setup project in Visual Studio to install your new Windows Services.
|
Visual Studio Command Prompt (run as Administrator) |
10) Start Service and test
Now go to your local services and start the new Windows Service. Then start watch the log while adding a new file in the folder that you are watching.
|
The new Windows Service |
|
Log file |
Download Visual Studio 2010 Example Project
Note: This Windows Service must be installed on the same machine as SSIS.