Using class library in SSIS Projects without GAC installation

I don’t want to add custom assembly in GAC. Here is my research.

There is no direct way to do that from integration services packages, because the only workaround is using CurrentDomain_AssemblyResolve function – loading an assembly from a location instead of installing it into GAC.

There are 3 ways for using custom dll’s on deployment:

  • Assigning DLL’s to the GAC
  • Using the AssemblyResolve Function
  • Copy all Dll’s to the sql server DTS Assemblies folder (example for SQL Server 2008: C:\Program Files\Microsoft SQL Server\100\DTS\Binn) and to the .Net framework assemblies folder.

There could be an interesting workaround by using a Web Service instead of direct dll, so you can create a web service which contains the methods you are using and add a Web reference instead of a Local assembly

Here is an example.

This might be your starting point.

Using custom DLL in script task

Resources

https://docs.microsoft.com/en-us/answers/questions/92003/unable-to-reference-custom-class-library-in-ssis-s.html

https://www.codeproject.com/Articles/895028/Refering-dlls-in-SSIS-Script-Task

https://www.dotnetspider.com/resources/45645-How-to-use-custom-DLL-in-SSIS-Package.aspx

Using email template to compose and send emails

This is a simple prototype to compose and send HTML emails using a sample template.

Here is the template;

String emailTemplate = @"
<html lang=""en"">
    <head>    
        <meta content=""text/html; charset=utf-8"" http-equiv=""Content-Type"">
        <title>
            {0}
        </title>
        <style type=""text/css"">
            HTML{background-color: #e8e8e8;}
            .document-table{font-size: 12px; padding: 3px; border-collapse: collapse; border-spacing: 0;}
            .document-table .description{color: #505050;}
            .document-table td{border: 1px solid #D1D1D1; background-color: #F3F3F3; padding: 0 10px;}
            .document-table th{border: 1px solid #424242; color: #FFFFFF;text-align: left; padding: 0 10px;}
            .green{background-color: #6B9852;}
            .wrapper { margin-bottom: 20px;}
        </style>
    </head>
    <body>
        <div class=""wrapper"">
            Team,
        </div>
        <div class=""wrapper"">
            SampleDb data pull job {1} last night. The job is configured to run on {2} basis.
        </div>
        <div class=""wrapper"">
            SampleDb database is scanned between {3} for new documents. Following new document have been found and their data is copied over to the target database.
        </div>
        <div class=""wrapper"">
            <table class=""document-table"">
                <thead>
                    <tr>
                        <th class=""green"">AccountNumber</th>
                        <th class=""green"">FYQ</th>
                        <th class=""green"">DateAdded</th>
                        <th class=""green"">RowStatus</th>
                    </tr>
                </thead>
                <tbody>
                    {4}
                </tbody>
            </table>
        </div>
        <div class=""wrapper"">
            <h5><br /><br />This inbox is unattended. please do not reply to this email. This is an auto-generated message.</h5>
        </div>
    </body>
</html>
";

We can use dynamic and ExpandoObject to create data. Alternatively you can grab data from database;

var list = new List<dynamic>();
dynamic row = new ExpandoObject();
row.AccountNumber = "XYZ-100";
row.FYQ = "Q1 FY 1999";
row.DateAdded = "1999-07-28 19:38:00.000";
row.RowStatus = "processed";
list.Add(row);

We need to fill template placeholders;

StringBuilder sb = new StringBuilder();           
list.ForEach(x =>
{
   sb.Append("<tr>");
   sb.Append($"<td class='description'>{x.AwardNumber}</td>");
   sb.Append($"<td>{x.FYQ}</td>");
   sb.Append($"<td>{x.DateAdded}</td>");
   sb.Append($"<td>{x.RowStatus}</td>");
   sb.Append("</tr>");
});

replace all placeholders in HTML template;

string emailBody =
    emailTemplate.Replace("{0}", "A demo email body title")
    .Replace("{1}", "succeeded")
    .Replace("{2}", "yearly")
    .Replace("{3}", "01/01/1999 23.59.59 - 11/2/2021 02:00:00 AM")
    .Replace("{4}", sb.ToString());
               

Compose and send email out;

MailMessage mailMessage = new MailMessage();
mailMessage.From = new MailAddress("FromAdam@mail.com", "Sample Data Pull");
mailMessage.To.Add("ToJoe@mail.com");
mailMessage.Body = emailTemplate;
mailMessage.Subject = "Test email";
mailMessage.IsBodyHtml = true;
mailMessage.SubjectEncoding = Encoding.UTF8;
mailMessage.BodyEncoding = Encoding.UTF8;

//send email
using (var client = new SmtpClient("smtp-host-address"))
{
   //if true, user/pwd required, false network credentials will be used
   client.UseDefaultCredentials = true;
   if (client.UseDefaultCredentials)
   {
   client.Credentials = new NetworkCredential("FromAdmam@mail.com", "AdamSecretPassword");
   }
   client.EnableSsl = true;
   client.DeliveryMethod = SmtpDeliveryMethod.Network;
   client.Timeout = 3000;      //3 seconds
   client.Send(mailMessage);
}

Run your program and check your inbox. You will see HTML email with CSS style applied. The HTML table element is replace with our created data.

Have fun!

Dataset is empty, no tables in Dataset

This is how we can test if dataset is empty;

if(ds != null)
if(ds.Tables.Count > 0 )
if(ds.Tables[0].Rows.Count > 0)

We can loop through all tables in a method like this;

bool IsEmpty(DataSet dataSet)
{
    foreach(DataTable table in dataSet.Tables)
        if (table.Rows.Count != 0) return false;

    return true;
}

Since a DataTable could contain deleted rows RowState = Deleted, depending on what you want to achive, it could be a good idea to check the DefaultView instead (which does not contain deleted rows).

bool IsEmpty(DataSet dataSet)
{
    return !dataSet.Tables.Cast<DataTable>().Any(x => x.DefaultView.Count > 0);
}

Resource

https://stackoverflow.com/questions/2976473/how-to-test-if-a-dataset-is-empty

Dynamic type and Expando Object class

The dynamic type indicates that use of the variable and references to its members bypass compile-time type checking. Instead, these operations are resolved at run time. The dynamic type simplifies access to COM APIs such as the Office Automation APIs, to dynamic APIs such as IronPython libraries, and to the HTML Document Object Model (DOM).

Here is an example;

var list = new List<dynamic>();
dynamic row = new ExpandoObject();
row.AccountNumber = "XYZ-331";
row.FYQ = "Q3 FY 2021";
row.DateAdded = "2021-07-28 19:38:00.000";
row.RowStatus = "processed";
list.Add(row);

Here is the output;

list.ForEach(x =>
{
   Console.WriteLine($"AccountNumber = { x.AccountNumber} \nFYQ =  {x.FYQ}\nDateAdded = {x.DateAdded}\nRowStatus = {row.RowStatus}");
});

Resources

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/reference-types

https://docs.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-5.0

https://www.codegrepper.com/code-examples/csharp/add+static+data+to+list+in+c%23