Friday, October 10, 2014

CDC in SSIS for SQL Server 2012

SQL Server 2012 introduces new components that make it easier to do Change Data Capture (CDC) using SSIS. This blog post provides a quick walkthrough of how to use them.

New Task and Components
CDC Control Task
The CDC Control task is used to control the life cycle of change data capture (CDC) packages. It handles CDC package synchronization with the initial load package, the management of Log Sequence Number (LSN) ranges that are processed in a run of a CDC package. In addition, the CDC Control task deals with error scenarios and recovery.

CDC Source
The CDC source reads a range of change data from CDC change tables and delivers the changes downstream to other SSIS components.

CDC Splitter
The CDC splitter splits a single flow of change rows from a CDC Source component into different data flows for Insert, Update and Delete operations. It is essentially a “smart” Conditional Split transform that automatically handles the standard values of the __$operation column.


Walkthrough

Database Setup

For sample data, we will create a new database (CDCTest), and select a subset of rows from the AdventureWorksDW DimCustomer table into a sample table (DimCustomer_CDC). This will become the Source table for this demo.

USE [CDCTest]
GO

SELECT * INTO DimCustomer_CDC
FROM [AdventureWorksDW].[dbo].[DimCustomer]
WHERE CustomerKey < 1000

We then enable CDC on the database, and create a capture instance for the DimCustomer_CDC table.

USE [CDCTest]
GO

EXEC sys.sp_cdc_enable_db
GO

-- add a primary key to the DimCustomer_CDC table so we can enable support for net changes
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[DimCustomer_CDC]') AND name = N'PK_DimCustomer_CDC')
  ALTER TABLE [dbo].[DimCustomer_CDC] ADD CONSTRAINT [PK_DimCustomer_CDC] PRIMARY KEY CLUSTERED 
(
    [CustomerKey] ASC
)
GO

EXEC sys.sp_cdc_enable_table 
@source_schema = N'dbo',
@source_name = N'DimCustomer_CDC',
@role_name = N'cdc_admin',
@supports_net_changes = 1

GO

We can see that a number of tables have been added under the cdc schema, and that SQL agent jobs have been created to capture changes being made to this table.



For the Destination, we’ll create a separate table – DimCustomer_Destination – with the same structure as the Source.

SELECT TOP 0 * INTO DimCustomer_Destination
FROM DimCustomer_CDC

In real life this would be in a separate database, and usually on a completely different server (otherwise, why are you mirroring the changes?), but for the purposes of this walkthrough, we’ll keep it all together.

We’re ready to start consuming changes with SSIS.

SSIS Packages

Our processing logic will be split into two packages – an Initial Load package that will read all of the data in the source table, and an Incremental Load package that will process change data on subsequent runs.

Initial Load

This package will only be run once, and handles the initial load of data in the source table (DimCustomer_CDC). The package uses the following logic:
  • Use the CDC Control Task to mark the initial load start LSN
  • Transfer all of the data from the source table into our destination table
  • Use the CDC Control Task to mark the initial load end LSN

Package creation steps:

Create a new SSIS package

Add a CDC Control Task. Double click the Control Task to bring up the editor.

  • Add a new ADO.NET connection manager for the Source database
  • Set CDC Control Operation to Mark initial load start
  • Create a new package variable (CDC_State) to hold the CDC state information.
  • Set the connection manager for the Destination database
  • Create a table for storing the state ([cdc_states]). This table will be used to track the CDC load information, so that you only pick up new changes each time the incremental load package is run. It will be created in the Destination database.
  • Set the state name (CDC_State). This value acts as a key for the CDC state information. Packages that are accessing the same CDC data should be using a common CDC state name.


Add a Data Flow Task, and connect it to the CDC Control Task

Configure the Data Flow task to transfer all of the data from the Source to the Destination

Add a second CDC Control Task. Connect the success constraint of the Data Flow Task to it.

Configure the second CDC Control Task with the same settings as the first one, except the CDC Control Operation should be set to Mark initial load end.


The package will now look like this:


When we run the package, all of the data currently in the Source table will be transferred to the Destination, and the initial CDC state markers will be created. If we select from the cdc_states table, we can see that there is now a “CDC_State” entry. Note, the state entry is an encoded string that is used by the CDC components – you should not have to edit or deal with it directly.

Incremental Load

This package will be run every time we want to grab the latest changes from our Source table. It will store the CDC state every time it runs, ensuring that we only pick up new changes every time we run the package. It will use the following logic:
  • Create staging tables for updated and deleted rows (so we can process the changes in a batch – more about that below)
  • Use a CDC Control Task to retrieve the CDC state from the destination table
  • Use a CDC Source to retrieve our change data
  • Use a CDC Splitter transform to redirect the rows based on their operation (New, Updated, and Deleted)
  • Insert the new rows into the Destination table
  • Stage the Updated and Deleted rows
  • Process the Updated and Deleted rows using Execute SQL Tasks
  • Use a CDC Control Task to update the CDC state

Package creation steps:

Add an Execute SQL Task to create staging tables
  • Create a connection manager for the Destination database (set the ConnectionType to ADO.NET to reuse the same connection manager used by the CDC Control Task)
  • Enter the SQL statements to create two staging tables that match the Destination table. For example:

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[stg_DimCustomer_UPDATES]') AND type in (N'U'))
BEGIN
   SELECT TOP 0 * INTO stg_DimCustomer_UPDATES
   FROM DimCustomer_Destination
END

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[stg_DimCustomer_DELETES]') AND type in (N'U'))
BEGIN
   SELECT TOP 0 * INTO stg_DimCustomer_DELETES
   FROM DimCustomer_Destination
END

Add a CDC Control Task. Connect the Execute SQL task to the CDC Control Task
  • Create a connection manager for the Source database
  • Set the CDC Control Operation to Get processing range
  • Create a new CDC state variable (CDC_state)
  • Create a connection manager for the Destination database
  • Select the state table (this was created by the Initial Load package) – [dbo].[cdc_states]
  • Set the State name – this must match what was used in the Initial Load package (CDC_State)


Add a Data Flow Task. Connected it to the CDC Control Task.

Add a CDC Source component
  • Set the Connection Manager to the Source database
  • Select the source table (DimCustomer_CDC)
  • Set the CDC processing mode to Net
  • Select the CDC_State variable
  • Click the Columns tab to make sure we’re pulling back all of the right information, then click OK.


Add a CDC Splitter transform

Add an ADO.NET Destination – rename it to “New rows”
  • Connect the InsertOutput of the CDC Splitter to the “New rows” destination
  • Double click the “New rows” destination to bring up its editor
  • Set the Destination connection manager, and select the main destination table (DimCustomer_Destination)
  • Click the Mappings tab. The columns should automatically match by name. The CDC columns (the ones starting with __$) can be ignored

Add two more ADO.NET Destinations, mapping the DeleteOutput to the stg_DimCustomer_DELETES table, and UpdateOutput to stg_DimCustomer_UPDATES. We will update the final Destination table using batch SQL statements after this data flow. An alternative design here would be to use an OLE DB Command transform to perform the updates and deletes. The OLE DB Command approach has some performance problems though, as the transform operates on a row by row basic (i.e. it issues one query per row).


Back in the Control Flow, add two Execute SQL tasks. These tasks will perform the batch update/delete using the data we loaded into the staging tables. The queries look like this (note, I took columns out of the update statement to keep things short – normally you’d include all of the columns here):

-- These queries go into the incremental load package, and do not need to be run directly
-- batch update

UPDATE dest
SET 
    dest.FirstName = stg.FirstName, 
    dest.MiddleName = stg.MiddleName,
    dest.LastName = stg.LastName, 
    dest.YearlyIncome = stg.YearlyIncome
FROM 
    [DimCustomer_Destination] dest, 
    [stg_DimCustomer_UPDATES] stg
WHERE 
    stg.[CustomerKey] = dest.[CustomerKey]

-- batch delete
DELETE FROM [DimCustomer_Destination]
  WHERE[CustomerKey] IN 
(
    SELECT [CustomerKey]
    FROM [dbo].[stg_DimCustomer_DELETES]
)

Add a CDC Control Task. It should have the same settings as the first CDC Control Task in the package, except the CDC control operation is Mark processed range.

Finally, add an Execute SQL Task to drop the staging tables. Alternatively, you can leave the staging tables in place, just truncate them.

Your package should look like this:


Running the Incremental Load Package

If we run the Incremental Load package at this point, it should run successfully, but not transfer any rows. That’s because we haven’t made any changes yet to the Source table. Let’s do that now by running the following script against the Source table:

USE [CDCTest]
GO

-- Transfer the remaining customer rows
SET IDENTITY_INSERT DimCustomer_CDC ON

INSERT INTO DimCustomer_CDC
(
       CustomerKey, GeographyKey, CustomerAlternateKey, Title, FirstName, 
       MiddleName, LastName, NameStyle, BirthDate, MaritalStatus, 
       Suffix, Gender, EmailAddress, YearlyIncome, TotalChildren, 
       NumberChildrenAtHome, EnglishEducation, SpanishEducation,
       FrenchEducation, EnglishOccupation, SpanishOccupation, 
       FrenchOccupation, HouseOwnerFlag, NumberCarsOwned, AddressLine1, 
       AddressLine2, Phone, DateFirstPurchase, CommuteDistance
)
SELECT CustomerKey, GeographyKey, CustomerAlternateKey, Title, FirstName, 
       MiddleName, LastName, NameStyle, BirthDate, MaritalStatus, 
       Suffix, Gender, EmailAddress, YearlyIncome, TotalChildren, 
       NumberChildrenAtHome, EnglishEducation, SpanishEducation,
       FrenchEducation, EnglishOccupation, SpanishOccupation, 
       FrenchOccupation, HouseOwnerFlag, NumberCarsOwned, AddressLine1, 
       AddressLine2, Phone, DateFirstPurchase, CommuteDistance
FROM [AdventureWorksDW].[dbo].[DimCustomer]
WHERE CustomerKey &lt; 500

SET IDENTITY_INSERT DimCustomer_CDC OFF
GO

-- give 10 people a raise
UPDATE DimCustomer_CDC 
SET 
    YearlyIncome = YearlyIncome + 10
WHERE
    CustomerKey &lt;= 11000 AND CustomerKey &gt;= 11010

GO

If we enable a Data Viewer in the Incremental Load package and run it, we’ll see that the CDC Source picks up all of the rows we’ve changed. We can see that some of the rows are __$operation = 4 (update), while the rest are 2 (new rows).


When the package completes, we see that the data flow moved a total of 17,995 rows (11 updates, and the rest are inserts).


Because the CDC Control Task updated LSN values stored in the CDC state table, if we run the package a second time (without making any changes to the source table), we see that no rows get transferred in the data flow.




Finish...


Tuesday, August 19, 2014

How to automatically refresh PivotTable in excel

Below is the C# code to refresh the pivottable in excel workbook


using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using Microsoft.Office.Interop.Excel;
--------------------


public void Main()

{
// TODO: Add your code here
            string path = Dts.Variables["$Project::RefreshExcel_Path"].Value.ToString();
            string filename = Dts.Variables["$Project::RefreshExcel_FileName"].Value.ToString();

            PivotRefresh(path + filename);

            Dts.TaskResult = (int)ScriptResults.Success;
}
        
        private void PivotRefresh(string Filename)
        {
            Microsoft.Office.Interop.Excel.Application oXL = new Microsoft.Office.Interop.Excel.Application();

            //oXL.Visible = true;

            oXL.DisplayAlerts = false;
            Microsoft.Office.Interop.Excel.Workbook mWorkBook = oXL.Workbooks.Open(Filename, 0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
            //Get all the sheets in the workbook
            Microsoft.Office.Interop.Excel.Sheets mWorkSheets = mWorkBook.Worksheets;
            foreach (Microsoft.Office.Interop.Excel.Worksheet pivotSheet in mWorkSheets)
            {
                //Microsoft.Office.Interop.Excel.PivotTables pivotTables = pivotSheet.PivotTables();
                Microsoft.Office.Interop.Excel.PivotTables pivotTables = (Microsoft.Office.Interop.Excel.PivotTables)pivotSheet.PivotTables();
                int pivotTablesCount = pivotTables.Count;
                if (pivotTablesCount > 0)
                {
                    for (int i = 1; i <= pivotTablesCount; i++)
                    {
                        pivotTables.Item(i).RefreshTable(); //The Item method throws an exception
                    }
                }
            }
            mWorkBook.Save();
            mWorkBook.Close(false, Filename, null);
            oXL.Quit();
            mWorkBook = null;
            System.Runtime.InteropServices.Marshal.ReleaseComObject(oXL);
        }

Thursday, August 14, 2014

Refresh the excel file using SSIS

C# code to refresh the excel report using SSIS Script task:

using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using Microsoft.Office.Interop.Excel;
--------------------
public void Main()
        {
            // TODO: Add your code here
            ExcelRefresh(@"E:\TEST.xls");
            Dts.TaskResult = (int)ScriptResults.Success;
        }
     
        private void ExcelRefresh(string Filename)
        {
            object NullValue = System.Reflection.Missing.Value;
            Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.ApplicationClass();
            excelApp.DisplayAlerts = false;
            Microsoft.Office.Interop.Excel.Workbook Workbook = excelApp.Workbooks.Open(
               Filename, NullValue, NullValue, NullValue, NullValue,
               NullValue, NullValue, NullValue, NullValue, NullValue,
               NullValue, NullValue, NullValue, NullValue, NullValue);
            Workbook.RefreshAll();
            System.Threading.Thread.Sleep(20000);
                     
            Workbook.Save();
            Workbook.Close(false, Filename, null);
            excelApp.Quit();
            Workbook = null;
            System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp);
        }
-------------
Incase if you get any error like 'Cannot be embbedded. Use the applicable interface instead [duplicate]' then 
follow the below step:

Go to References - find the Microsoft Office Interop reference - Right click - select properties 
- change 'Embed Intero Types' to false.

Tuesday, August 5, 2014

How to remove rows from csv file using script task

Below is the C# code to remove specified rows from CSV file using script task

Add following references:

using System.IO;

using System.Collections.Generic;

Code
------

string line;
            StreamReader sr = new StreamReader(@"E:\Test.csv");

            List<String> file = new List<string>();
            
            while (sr.Peek() >= 0)
            {
                line = sr.ReadLine();
                if (line != "")
                {
                    if (!line.StartsWith("#")) //line starts with #
                    {
                        if (!line.Contains("Summary"))   //line contains string as summary
                        {
                            file.Add(line);
                        }
                    }
                }
            }
            sr.Close();
          
            File.WriteAllLines(@"E:\Test1.csv", file);
            //File.WriteAllLines(@"E:\Test.csv", file);

How to remove rows from excel using script task

Below is the C# code to remove selected rows from Excel work sheet using script task in SSIS

Add the following references: 

using Microsoft.Office.Interop.Excel;
using Microsoft.CSharp;

using System.Diagnostics;

Code
-------

Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
            // open the concrete file:
            Microsoft.Office.Interop.Excel.Workbook excelWorkbook = excel.Workbooks.Open(@"E:\RemoveRows.xlsx");
            // select worksheet. NOT zero-based!!:
            Microsoft.Office.Interop.Excel._Worksheet excelWorkbookWorksheet = excelWorkbook.Sheets[1];
            // create a range:
            Microsoft.Office.Interop.Excel.Range range = excelWorkbookWorksheet.get_Range("A1:A2");
            Microsoft.Office.Interop.Excel.Range range2 = excelWorkbookWorksheet.get_Range("A4");
            Microsoft.Office.Interop.Excel.Range entireRow = range.EntireRow;
            Microsoft.Office.Interop.Excel.Range entireRow2 = range2.EntireRow;

            // iterate range
            
            entireRow.Delete(Microsoft.Office.Interop.Excel.XlDeleteShiftDirection.xlShiftUp);
            entireRow2.Delete(Microsoft.Office.Interop.Excel.XlDeleteShiftDirection.xlShiftUp);
           

            // save changes (!!):
            excelWorkbook.Save();

            excel.Quit();

Dts.TaskResult = (int)ScriptResults.Success;

Thursday, July 24, 2014

To send email when package failed or successed

Create user(project) variables to have exchange server name, from email id, to email id and subject.

Get script task in evenhandler at OnError event. Select the below mentioned varibles in Read only variable option and apply the script

System::ErrorDescription
System::SourceName
System::PackageName
System::StartTime

$Project::ExchangeServerName
$Project::MailFrom
$Project::MailTo
$Project::Subject

//required namespaces
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.Net.Mail;
using System.Text;

public void Main()
{
// TODO: Add your code here
            string MessageTo = Dts.Variables["$Project::MailTo"].Value.ToString();
            string MessageFrom = Dts.Variables["$Project::MailFrom"].Value.ToString();
            DateTime StartTime = (DateTime)Dts.Variables["System::StartTime"].Value;
            string packagename = Dts.Variables["System::PackageName"].Value.ToString();
            string MessageSubject = packagename + " " + "Package Failed";
            string sourcename = Dts.Variables["System::SourceName"].Value.ToString();
            string MessageBody = Dts.Variables["System::ErrorDescription"].Value.ToString();
            string smtpServer = Dts.Variables["$Project::ExchangeServerName"].Value.ToString();



            SendMailMessage(MessageTo, MessageFrom, StartTime, packagename, MessageSubject, sourcename, MessageBody, true, smtpServer);

Dts.TaskResult = (int)ScriptResults.Success;
}
        private void SendMailMessage(string SendTo, string From, DateTime Starttime, string Subject, string packagename, string sourcename, string Body, bool IsBodyHtml, string Server)
        {

            MailMessage htmlMessage;
            SmtpClient mySmtpClient;

            htmlMessage = new MailMessage(SendTo, From, Subject, Body);
            StringBuilder mailstring = new StringBuilder();
            mailstring.Append("<html><body>" + "<table border='1' width='100%'> <tr border=2 bgcolor='gray'><td border=2>Start Time</td><td>Package Name</td><td>Source Name</td><td>Error Description</td></tr><tr> <td border=2>"
            + Starttime + "</td><td>" +packagename + "</td><td>" + sourcename + "</td><td>" + Body + "</td></tr> </table></body></html>");
           

            mySmtpClient = new SmtpClient(Server);
            mySmtpClient.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
           
            htmlMessage.IsBodyHtml = true;
            htmlMessage.Body = mailstring.ToString();
            mySmtpClient.Send(htmlMessage);
        }

Database Management

To view the database size: I have used 3 types of option to view database size:

EXEC sp_spaceused

SELECT DB_NAME(database_id) AS DatabaseName,
Name AS Logical_Name,
Physical_Name, (size*8)/1024 SizeMB
FROM sys.master_files
WHERE DB_NAME(database_id) = 'TestDB'
GO

SELECT 
      database_name = DB_NAME(database_id)
    , log_size_mb = CAST(SUM(CASE WHEN type_desc = 'LOG' THEN size END) * 8. / 1024 AS DECIMAL(8,2))
    , row_size_mb = CAST(SUM(CASE WHEN type_desc = 'ROWS' THEN size END) * 8. / 1024 AS DECIMAL(8,2))
    , total_size_mb = CAST(SUM(size) * 8. / 1024 AS DECIMAL(8,2))
FROM sys.master_files WITH(NOWAIT)
WHERE database_id = DB_ID() -- for current db 
GROUP BY database_id

Some of the Maintenance DBCC Statements are:
DBCC CLEANTABLE

DBCC INDEXDEFRAG (databasename, tablename,indexname)
defragment clustered and nonclustered indexes on tables and views

DBCC DBREINDEX(tablename)
rebuilds an index for a table or all indexes defined for a table.

DBCC SHRINKDATABASE(databasename)
Shrinks the size of the data and log files in the specified database
Avoid executing this command during busy periods in production

DBCC SHRINKFILE(file_id) Use exec sp_helpfile
allows you to shrink the size of individual data and log files
Avoid, as in most cases the database will just regrow and shrinking data files causes fragmentation.

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
DBCC SHRINKFILE
DBCC UPDATEUSAGE

Some of the Miscellaneous DBCC Statements are:
DBCC dllname (FREE)
DBCC HELP
DBCC FREESESSIONCACHE 
DBCC TRACEOFF - used to disable tracing
DBCC FREESYSTEMCACHE
DBCC TRACEON - used to enable tracing

Some of the Informational DBCC Statements are:
DBCC INPUTBUFFER(sessionid)
to view the last statement sent by the client connection to SQL Server

DBCC SHOWCONTIG
DBCC OPENTRAN

DBCC SQLPERF(logspace)
To see transaction log size of each database on Server

DBCC SHOWFILESTATS
Show Total Extents and used extents for database

DBCC OUTPUTBUFFER

DBCC TRACESTATUS
used to know trace status with TraceFlag,Status,Global,Session

DBCC PROCCACHE

DBCC USEROPTIONS
Returns the SET options active (set) for the current connection

DBCC SHOW_STATISTICS


Some of the Validation DBCC Statements are:
DBCC CHECKALLOC
checks page usage and allocation in the database.

DBCC CHECKFILEGROUP

DBCC CHECKCATALOG
Checks for catalog/tables consistency within the specified database

DBCC CHECKIDENT

DBCC CHECKCONSTRAINTS 
Checks the integrity of a specified constraint or all constraints on a specified table in the current database

DBCC CHECKTABLE(tablename)
It verifies index and data page links, index sort order, page pointers, index pointers, data page integrity, and page offsets on table.

DBCC CHECKDB

T-SQL Query to find all members in server role:

SELECT SUSER_NAME(members.role_principal_id) AS [ServerRole]
   ,logins.name AS 'RoleMember'
   ,'EXEC sp_addsrvrolemember ''' +logins.name+''', '''+
   SUSER_NAME(members.role_principal_id)+'''' AS [Command to add role members]
FROM sys.server_role_members members, sys.server_principals logins
WHERE members.role_principal_id >=3 AND members.role_principal_id <=10 AND
members.member_principal_id = logins.principal_id
--and logins.name <>'sa' --Excluding system administrator

T-SQL to get the list of objects modified in x number of days:

DECLARE @Days int
SET @Days=300 -- Specify the number of days
SELECT name AS ObjectName
  ,SCHEMA_NAME(schema_id) AS SchemaName
  ,type_desc AS ObjectType
  ,create_date AS ObjectCreatedOn
  ,modify_date As ObjectModifiedOn
FROM sys.objects
WHERE modify_date > GETDATE() - @Days
ORDER BY modify_date;
GO




Monday, July 7, 2014

Retrieve data from Distimo - Mobile Application

Below is the code to retrieve mobile application downloads data from Distimo API

public void Main()
{
// Returns assets in json format
string api = "https://api.distimo.com/v4/downloads";

DateTime FromDate = (DateTime)Dts.Variables["User::FromDate"].Value;
string s = FromDate.ToString("yyyy-MM-dd");
DateTime ToDate = (DateTime)Dts.Variables["User::ToDate"].Value;
string s1 = ToDate.ToString("yyyy-MM-dd");


//string query = "format=csv&from=2010-12-01&to=2010-12-31&breakdown=application,appstore";
string query = "format=csv" + "&" + "from=" + s + "&" + "to=" + s1 + "&breakdown=application,appstore";

// Necessary variables

string publicKey = (string)Dts.Variables["User::PublicKey"].Value;
string privateKey = (string)Dts.Variables["User::PrivateKey"].Value;
string userName = (string)Dts.Variables["User::UserName"].Value;
string password = (string)Dts.Variables["User::Password"].Value;

// Identify application
int time = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;
string data = String.Concat(query, time);
HMACSHA1 hmac = new HMACSHA1(Encoding.ASCII.GetBytes(privateKey));
hmac.Initialize();

byte[] buffer = Encoding.ASCII.GetBytes(data);
string hash = BitConverter.ToString(hmac.ComputeHash(buffer)).Replace("-", "").ToLower();
string user = String.Concat(userName, ":", password);
string base64Login = Convert.ToBase64String(Encoding.Default.GetBytes(user));

// Make the request
string url = api + "?" + query + "&apikey=" + publicKey + "&hash=" + hash + "&t=" + time;
WebRequest request = WebRequest.Create(url);
request.Headers["Authorization"] = String.Concat("Basic ", base64Login);

//MessageBox.Show(url);

string result;
try
{
result = new StreamReader(request.GetResponse().GetResponseStream()).ReadToEnd();
}
catch (WebException e)
{
result = new StreamReader(e.Response.GetResponseStream()).ReadToEnd();
}

System.IO.File.WriteAllText(@"D:\MobileApp_Distimo\MobileApp_Downloads.txt", result);

Dts.TaskResult = (int)ScriptResults.Success;
}