I am using SQL Server Data Tools 2013 to create an SSIS package. This package has an Execute SQL Task with a Full Resultset option to push the query results into an SSIS Variable, of type Object.
I'm using the following in a script task to take a recordset stored in an object variable and write it to a CSV:
Public Sub Main()
Dim fileName As String = Dts.Variables("vFileName").Value.ToString
Dim destinationPath As String = Dts.Variables("vDestinationPath").Value.ToString
Dim destinationPathAndFileName As String = destinationPath + fileName
Dim fileContents As String = ""
Dim oleDB As OleDbDataAdapter = New OleDbDataAdapter()
Dim table As DataTable = New DataTable()
Dim rs As System.Object = Dts.Variables("vResultSet").Value
' Populate DataTable with vResultSet data
oleDB.Fill(table, rs)
' Loop through columns and concatenate with commas
For Each col As DataColumn In table.Columns
fileContents &= col.ColumnName & ","
Next
' Remove final comma from columns string and append line break
fileContents = fileContents.Substring(0, fileContents.Length - 1)
fileContents &= Environment.NewLine
' Loop through rows and concatenate with commas
Dim i As Integer
For Each row As DataRow In table.Rows
For i = 1 To table.Columns.Count
fileContents &= row(i - 1).ToString() & ","
Next
' Remove final comma from row string and append line break
fileContents = fileContents.Substring(0, fileContents.Length - 1)
fileContents &= Environment.NewLine
Next
' Write all text to destination file. If file exists, this step will overwrite it.
System.IO.File.WriteAllText(destinationPathAndFileName, fileContents)
Dts.TaskResult = ScriptResults.Success
End Sub
This works, but it's veeeery slow, like 25+ minutes to write a single 14k-row dataset to CSV. I can't use a data flow because this process exists in a loop, and the metadata for each table to be exported is different. I'm pretty sure a script task is the only option, but is there a faster way than looping through each row of the dataset? Please let me know if I can provide more info.
Feel free to translate to VB.NET as you see fit. Seeing as how I already have this code ~ written for a different project, I mashed your request in with how mine works
Passing in 3 SSIS variables: vFileName, vDestinationPath and vResultSet, the code in Main will convert the ado recordset into a DataTable which is then added to a DataSet and passed to the Persist method. Persist has a default parameter for delimiter of |.
This implementation does not attempt to deal with any of the corner cases, at all. It does not escape text columns with a qualifier, doesn't escape embedded qualifiers, do anything with newlines in the feeds and something in the OleDbDataAdapter's fill method fails with binary data, etc
public void Main()
{
string fileName = Dts.Variables["User::vFileName"].Value.ToString();
DataSet ds = null;
DataTable dt = null;
string outputFolder = Dts.Variables["User::vDestinationPath"].Value.ToString();
string fileMask = string.Empty;
string sheetName = string.Empty;
string outSubFolder = string.Empty;
string message = string.Empty;
bool fireAgain = true;
try
{
ds = new DataSet();
dt = new DataTable();
System.Data.OleDb.OleDbDataAdapter adapter = new System.Data.OleDb.OleDbDataAdapter();
adapter.Fill(dt, Dts.Variables["User::vResultSet"].Value);
string baseFileName = System.IO.Path.GetFileNameWithoutExtension(fileName);
baseFileName = System.IO.Path.GetFileName(fileName);
ds.Tables.Add(dt);
//foreach (DataTable dt in ds.Tables)
{
Persist(ds, fileName, outputFolder);
}
}
catch (Exception ex)
{
Dts.Events.FireInformation(0, "Data Dumper", string.Format("{0}|{1}", "fileName", fileName), string.Empty, 0, ref fireAgain);
Dts.Events.FireInformation(0, "Data Dumper", string.Format("{0}|{1}", "outputFolder", outputFolder), string.Empty, 0, ref fireAgain);
Dts.Events.FireInformation(0, "Data Dumper", string.Format("{0}|{1}", "ExceptionDetails", ex.ToString()), string.Empty, 0, ref fireAgain);
Dts.Events.FireInformation(0, "Data Dumper", string.Format("{0}|{1}", "InnerExceptionDetails", ex.InnerException), string.Empty, 0, ref fireAgain);
}
Dts.TaskResult = (int)ScriptResults.Success;
}
public static void Persist(System.Data.DataSet ds, string originalFileName, string outputFolder, string delimiter = "|")
{
// Enumerate through all the tables in the dataset
// Save it out as sub versions of the
if (ds == null)
{
return;
}
string baseFileName = System.IO.Path.GetFileNameWithoutExtension(originalFileName);
string baseFolder = System.IO.Path.GetDirectoryName(originalFileName);
System.Collections.Generic.List<string> header = null;
foreach (System.Data.DataTable table in ds.Tables)
{
string outFilePath = System.IO.Path.Combine(outputFolder, string.Format("{0}.{1}.csv", baseFileName, table.TableName));
System.Text.Encoding e = System.Text.Encoding.Default;
if (table.ExtendedProperties.ContainsKey("Unicode") && (bool)table.ExtendedProperties["Unicode"])
{
e = System.Text.Encoding.Unicode;
}
using (System.IO.StreamWriter file = new System.IO.StreamWriter(System.IO.File.Open(outFilePath, System.IO.FileMode.Create), e))
{
table.ExtendedProperties.Add("Path", outFilePath);
// add header row
header = new System.Collections.Generic.List<string>(table.Columns.Count);
foreach (System.Data.DataColumn item in table.Columns)
{
header.Add(item.ColumnName);
}
file.WriteLine(string.Join(delimiter, header));
foreach (System.Data.DataRow row in table.Rows)
{
// TODO: For string based fields, capture the max length
IEnumerable<string> fields = (row.ItemArray).Select(field => field.ToString());
file.WriteLine(string.Join(delimiter, fields));
}
}
}
}
Need to run but a Biml implementation looks like
<Biml xmlns="http://schemas.varigence.com/biml.xsd">
<Connections>
<OleDbConnection Name="tempdb" ConnectionString="Data Source=localhost\dev2014;Initial Catalog=AdventureWorksDW2014;Provider=SQLNCLI11.0;Integrated Security=SSPI;"/>
</Connections>
<Packages>
<Package Name="so_37059747" ConstraintMode="Linear">
<Variables>
<Variable DataType="String" Name="QuerySource"><![CDATA[SELECT
S.name
, T.name
FROM
sys.schemas AS S
INNER JOIN
sys.tables AS T
ON T.schema_id = S.schema_id;]]></Variable>
<Variable DataType="String" Name="SchemaName">dbo</Variable>
<Variable DataType="String" Name="TableName">foo</Variable>
<Variable DataType="String" Name="QueryTableDump" EvaluateAsExpression="true">"SELECT X.* FROM [" + #[User::SchemaName] + "].[" + #[User::TableName] + "] AS X;"</Variable>
<Variable DataType="Object" Name="rsTables"></Variable>
<Variable DataType="Object" Name="vResultSet"></Variable>
<Variable DataType="String" Name="vFileName" EvaluateAsExpression="true">#[User::SchemaName] + "_" + #[User::TableName] + ".txt"</Variable>
<Variable DataType="String" Name="vDestinationPath">c:\ssisdata\so\Output</Variable>
</Variables>
<Tasks>
<ExecuteSQL
ConnectionName="tempdb"
Name="SQL Generate Loop data"
ResultSet="Full">
<VariableInput VariableName="User.QuerySource" />
<Results>
<Result VariableName="User.rsTables" Name="0" />
</Results>
</ExecuteSQL>
<ForEachAdoLoop SourceVariableName="User.rsTables" Name="FELC Shred rs" ConstraintMode="Linear">
<VariableMappings>
<VariableMapping VariableName="User.SchemaName" Name="0" />
<VariableMapping VariableName="User.TableName" Name="1" />
</VariableMappings>
<Tasks>
<ExecuteSQL
ConnectionName="tempdb"
Name="SQL Generate Export data"
ResultSet="Full">
<VariableInput VariableName="User.QueryTableDump" />
<Results>
<Result VariableName="User.vResultSet" Name="0" />
</Results>
</ExecuteSQL>
<Script ProjectCoreName="ST_RS2CSV" Name="SCR Convert to text">
<ScriptTaskProjectReference ScriptTaskProjectName="ST_RS2CSV" />
</Script>
</Tasks>
</ForEachAdoLoop>
</Tasks>
</Package>
</Packages>
<ScriptProjects>
<ScriptTaskProject ProjectCoreName="ST_RS2CSV" Name="ST_RS2CSV" VstaMajorVersion="0">
<ReadOnlyVariables>
<Variable Namespace="User" VariableName="vFileName" DataType="String" />
<Variable Namespace="User" VariableName="vDestinationPath" DataType="String" />
<Variable Namespace="User" VariableName="vResultSet" DataType="Object" />
</ReadOnlyVariables>
<Files>
<File Path="ScriptMain.cs" BuildAction="Compile">
<![CDATA[namespace DataDumper
{
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
using Microsoft.SqlServer.Dts.Runtime;
[Microsoft.SqlServer.Dts.Tasks.ScriptTask.SSISScriptTaskEntryPointAttribute]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
public void Main()
{
string fileName = Dts.Variables["User::vFileName"].Value.ToString();
DataSet ds = null;
DataTable dt = null;
string outputFolder = Dts.Variables["User::vDestinationPath"].Value.ToString();
string fileMask = string.Empty;
string sheetName = string.Empty;
string outSubFolder = string.Empty;
string message = string.Empty;
bool fireAgain = true;
try
{
ds = new DataSet();
dt = new DataTable();
System.Data.OleDb.OleDbDataAdapter adapter = new System.Data.OleDb.OleDbDataAdapter();
adapter.Fill(dt, Dts.Variables["User::vResultSet"].Value);
string baseFileName = System.IO.Path.GetFileNameWithoutExtension(fileName);
baseFileName = System.IO.Path.GetFileName(fileName);
ds.Tables.Add(dt);
//foreach (DataTable dt in ds.Tables)
{
Persist(ds, fileName, outputFolder);
}
}
catch (Exception ex)
{
Dts.Events.FireInformation(0, "Data Dumper", string.Format("{0}|{1}", "fileName", fileName), string.Empty, 0, ref fireAgain);
Dts.Events.FireInformation(0, "Data Dumper", string.Format("{0}|{1}", "outputFolder", outputFolder), string.Empty, 0, ref fireAgain);
Dts.Events.FireInformation(0, "Data Dumper", string.Format("{0}|{1}", "ExceptionDetails", ex.ToString()), string.Empty, 0, ref fireAgain);
Dts.Events.FireInformation(0, "Data Dumper", string.Format("{0}|{1}", "InnerExceptionDetails", ex.InnerException), string.Empty, 0, ref fireAgain);
}
Dts.TaskResult = (int)ScriptResults.Success;
}
public static void Persist(System.Data.DataSet ds, string originalFileName, string outputFolder, string delimiter = "|")
{
// Enumerate through all the tables in the dataset
// Save it out as sub versions of the
if (ds == null)
{
return;
}
string baseFileName = System.IO.Path.GetFileNameWithoutExtension(originalFileName);
string baseFolder = System.IO.Path.GetDirectoryName(originalFileName);
System.Collections.Generic.List<string> header = null;
foreach (System.Data.DataTable table in ds.Tables)
{
string outFilePath = System.IO.Path.Combine(outputFolder, string.Format("{0}.{1}.csv", baseFileName, table.TableName));
System.Text.Encoding e = System.Text.Encoding.Default;
if (table.ExtendedProperties.ContainsKey("Unicode") && (bool)table.ExtendedProperties["Unicode"])
{
e = System.Text.Encoding.Unicode;
}
using (System.IO.StreamWriter file = new System.IO.StreamWriter(System.IO.File.Open(outFilePath, System.IO.FileMode.Create), e))
{
table.ExtendedProperties.Add("Path", outFilePath);
// add header row
header = new System.Collections.Generic.List<string>(table.Columns.Count);
foreach (System.Data.DataColumn item in table.Columns)
{
header.Add(item.ColumnName);
}
file.WriteLine(string.Join(delimiter, header));
foreach (System.Data.DataRow row in table.Rows)
{
// TODO: For string based fields, capture the max length
IEnumerable<string> fields = (row.ItemArray).Select(field => field.ToString());
file.WriteLine(string.Join(delimiter, fields));
}
}
}
}
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
}
}
]]>
</File>
<File Path="Properties\AssemblyInfo.cs" BuildAction="Compile">
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: AssemblyTitle("AssemblyTitle")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Bill Fellows")]
[assembly: AssemblyProduct("ProductName")]
[assembly: AssemblyCopyright("Copyright # 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("1.0.*")]
</File>
</Files>
<AssemblyReferences>
<AssemblyReference AssemblyPath="System" />
<AssemblyReference AssemblyPath="System.Core" />
<AssemblyReference AssemblyPath="System.Data" />
<AssemblyReference AssemblyPath="System.Data.DataSetExtensions" />
<AssemblyReference AssemblyPath="System.Windows.Forms" />
<AssemblyReference AssemblyPath="System.Xml" />
<AssemblyReference AssemblyPath="Microsoft.SqlServer.ManagedDTS.dll" />
<AssemblyReference AssemblyPath="Microsoft.SqlServer.ScriptTask.dll" />
<AssemblyReference AssemblyPath="System.Linq" />
<AssemblyReference AssemblyPath="System.Xml.Linq" />
<AssemblyReference AssemblyPath="Microsoft.VisualBasic" />
</AssemblyReferences>
</ScriptTaskProject>
</ScriptProjects>
</Biml>
That dumped all of AdventureworksDW2014 in 15 seconds
Based on the comment that this line is failing IEnumerable<string> fields = (row.ItemArray).Select(field => field.ToString());
Ensure that you have the following using statements in your project. I think those extensions are in the Linq namespaces but it could have been the Collections
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
using Microsoft.SqlServer.Dts.Runtime;
Why was the original slow?
My assumption is the slowness boils down to all that concatenation. Strings are immutable in .Net and you are creating a new version of that string each time you add a column to it. When I build my line, I'm using the String.Join method to zip up each element an array into a single string. This also simplifies the logic required to append the field delimiters.
I also immediately write the current line to a file instead of bloating my memory just to dump it all with a call to WriteAllText
This is the VB.NET version of #billinkc's excellent answer in case it's useful to anyone:
Imports System
Imports System.Data
Imports System.Math
Imports System.Collections
Imports System.Collections.Generic
Imports Microsoft.SqlServer.Dts.Runtime
Imports System.Linq
Imports System.Text
Imports System.Windows.Forms
Public Sub Main()
Dim fileName As String = Dts.Variables("User::vFileName").Value.ToString()
Dim ds As DataSet = Nothing
Dim dt As DataTable = Nothing
Dim outputFolder As String = Dts.Variables("User::vDestinationPath").Value.ToString()
Dim fileMask As String = String.Empty
Dim sheetName As String = String.Empty
Dim outSubFolder As String = String.Empty
Dim message As String = String.Empty
Dim fireAgain As Boolean = True
Try
ds = New DataSet()
dt = New DataTable()
Dim adapter As New System.Data.OleDb.OleDbDataAdapter()
adapter.Fill(dt, Dts.Variables("User::vResultSet").Value)
Dim baseFileName As String = System.IO.Path.GetFileNameWithoutExtension(fileName)
baseFileName = System.IO.Path.GetFileName(fileName)
ds.Tables.Add(dt)
'foreach (DataTable dt in ds.Tables)
If True Then
Persist(ds, fileName, outputFolder)
End If
Catch ex As Exception
Dts.Events.FireInformation(0, "Data Dumper", String.Format("{0}|{1}", "fileName", fileName), String.Empty, 0, fireAgain)
Dts.Events.FireInformation(0, "Data Dumper", String.Format("{0}|{1}", "outputFolder", outputFolder), String.Empty, 0, fireAgain)
Dts.Events.FireInformation(0, "Data Dumper", String.Format("{0}|{1}", "ExceptionDetails", ex.ToString()), String.Empty, 0, fireAgain)
Dts.Events.FireInformation(0, "Data Dumper", String.Format("{0}|{1}", "InnerExceptionDetails", ex.InnerException), String.Empty, 0, fireAgain)
End Try
Dts.TaskResult = CInt(ScriptResults.Success)
End Sub
Public Shared Sub Persist(ds As System.Data.DataSet, originalFileName As String, outputFolder As String, Optional delimiter As String = ",")
' Enumerate through all the tables in the dataset
' Save it out as sub versions of the
If ds Is Nothing Then
Return
End If
Dim baseFileName As String = System.IO.Path.GetFileNameWithoutExtension(originalFileName)
Dim baseFolder As String = System.IO.Path.GetDirectoryName(originalFileName)
Dim header As System.Collections.Generic.List(Of String) = Nothing
For Each table As System.Data.DataTable In ds.Tables
Dim outFilePath As String = System.IO.Path.Combine(outputFolder, String.Format("{0}.csv", baseFileName, table.TableName))
Dim e As System.Text.Encoding = System.Text.Encoding.[Default]
If table.ExtendedProperties.ContainsKey("Unicode") AndAlso CBool(table.ExtendedProperties("Unicode")) Then
e = System.Text.Encoding.Unicode
End If
Using file As New System.IO.StreamWriter(System.IO.File.Open(outFilePath, System.IO.FileMode.Create), e)
table.ExtendedProperties.Add("Path", outFilePath)
' add header row
header = New System.Collections.Generic.List(Of String)(table.Columns.Count)
For Each item As System.Data.DataColumn In table.Columns
header.Add(item.ColumnName)
Next
file.WriteLine(String.Join(delimiter, header))
For Each row As System.Data.DataRow In table.Rows
' TODO: For string based fields, capture the max length
Dim fields As IEnumerable(Of String) = (row.ItemArray).[Select](Function(field) field.ToString())
file.WriteLine(String.Join(delimiter, fields))
Next
End Using
Next
End Sub
Related
Here is the CSV data I am trying to import into my VB.NET app:
Raw Data
But when I run it through the app it only populates the last row:
Output
Here's the code for the import:
Private Sub btnBrowse_Click(sender As Object, e As EventArgs) Handles btnBrowse.Click
DataGridView1.ClearSelection()
ofd.Filter = "(*csv)|*.csv"
If ComboBox1.Text = "zVBImportTEST" Then
If (ofd.ShowDialog() = DialogResult.OK) Then
txtbxFilePath.Text = ofd.FileName
End If
Dim colsexpected As Integer = 6
Dim thereader As New StreamReader(txtbxFilePath.Text, Encoding.ASCII)
Dim sline As String = ""
thereader.ReadLine()
Do
sline = thereader.ReadLine
If sline Is Nothing Then Exit Do
Dim words() As String = sline.Split(",")
DataGridView1.Rows.Add("")
For ix As Integer = 0 To 5
DataGridView1.Rows(DataGridView1.Rows.Count - 1).Cells(ix).Value = words(ix)
Next
Loop
thereader.Close()
Else
MessageBox.Show("Please select a project.", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
End If
End Sub
I can't seem to figure out why the other rows are coming up blank.
If anyone could help me it would be greatly appreciated.
I would not suggest trying to read the data via a StreamReader, instead use the OleDb class while passing the connection string for a CSV file.
Here is a quick example of a function that returns a DataTable based on the contents of the CSV file:
Private Function ConvertCSVToDataTable(ByVal path As String) As DataTable
Dim dt As DataTable = New DataTable()
Using con As OleDb.OleDbConnection = New OleDb.OleDbConnection()
Try
con.ConnectionString = String.Format("Provider={0};Data Source={1};Extended Properties=""Text;HDR=YES;FMT=Delimited""", "Microsoft.Jet.OLEDB.4.0", IO.Path.GetDirectoryName(path))
Using cmd As OleDb.OleDbCommand = New OleDb.OleDbCommand("SELECT * FROM " & IO.Path.GetFileName(path), con)
Using da As OleDb.OleDbDataAdapter = New OleDb.OleDbDataAdapter(cmd)
con.Open()
da.Fill(dt)
con.Close()
End Using
End Using
Catch ex As Exception
Console.WriteLine(ex.ToString())
Finally
If con IsNot Nothing AndAlso con.State = ConnectionState.Open Then
con.Close()
End If
End Try
End Using
Return dt
End Function
Then here is how you'd bind your DataGridView:
DataGridView1.DataSource = Me.ConvertCSVToDataTable(ofd.FileName)
Update
Since you want to specify the data type of the DataColumn, declare a DataTable and assign it to the custom function, but then go in after the fact and change the data type of the specific columns. Here is a quick (free-typed and untested) example:
Dim csv As DataTable = Me.ConvertCSVToDataTable(ofd.FileName)
With csv.Columns
.Items(0).DataType = GetType(Int32)
.Items(1).DataType = GetType(Int32)
.Items(4).DataType = GetType(Int32)
.Items(5).DataType = GetType(Int32)
End With
DataGridView1.DataSource = csv
This is C# but the snippet shows what you are currently doing, and how to do it so that it works.
using System.Collections.Generic;
using System.Windows.Forms;
namespace DataGridNoBinding_47308996
{
public partial class Form1 : Form
{
DataGridView dgv = new DataGridView();
public Form1()
{
InitializeComponent();
dgv.Dock = DockStyle.Fill;
dgv.AutoGenerateColumns = false;
dgv.Columns.Add("Key","Key");
dgv.Columns.Add("Value", "Value");
this.Controls.Add(dgv);
Dictionary<string, string> dgvdata = new Dictionary<string, string>();
for (int i = 0; i < 10; i++)
{
dgvdata.Add($"key{i}", $"value{i}");
}
//AddToGridNoWork(dgvdata);
AddToGridDoesWork(dgvdata);
}
/// <summary>
/// This method does not work. This emulates what you are currently doing.
/// </summary>
/// <param name="dgvdata"></param>
private void AddToGridNoWork(Dictionary<string, string> dgvdata)
{
foreach (KeyValuePair<string, string> item in dgvdata)
{
dgv.Rows.Add();
dgv.Rows[dgv.Rows.Count - 1].Cells[0].Value = item.Key;
dgv.Rows[dgv.Rows.Count - 1].Cells[1].Value = item.Value;
dgv.Refresh();
}
}
/// <summary>
/// This method does work.
/// Add a new row to the Grid and store the new row index in rowindex
/// Then use the variable rowindex to update the correct row
/// </summary>
/// <param name="dgvdata"></param>
private void AddToGridDoesWork(Dictionary<string, string> dgvdata)
{
foreach (KeyValuePair<string, string> item in dgvdata)
{
int rowindex = dgv.Rows.Add();
dgv.Rows[rowindex].Cells[0].Value = item.Key;
dgv.Rows[rowindex].Cells[1].Value = item.Value;
}
}
}
}
In your VB.net application, it's probably just a matter of doing somehting like this
dim newRowIndex as Integer
newRowIndex = DataGridView1.Rows.Add("")
For ix As Integer = 0 To 5
DataGridView1.Rows(newRowIndex).Cells(ix).Value = words(ix)
Next
With DataDriver instead
Here's my code, re spun using a data driver instead of the StreamReader
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Data.OleDb;
using System.Data;
namespace DataGridNoBinding_47308996
{
public partial class Form1 : Form
{
DataGridView dgv = new DataGridView();
public Form1()
{
InitializeComponent();
dgv.Dock = DockStyle.Fill;
this.Controls.Add(dgv);
Dictionary<string, string> dgvdata = new Dictionary<string, string>();
for (int i = 0; i < 10; i++)
{
dgvdata.Add($"key{i}", $"value{i}");
}
//AddToGridNoWork(dgvdata);
//AddToGridDoesWork(dgvdata);
//AddToGridUsingDataDriver(#"M:\StackOverflowQuestionsAndAnswers\DataGridNoBinding_47308996\SampleData.csv");
AddToGridByBindingTheWholeTable(#"M:\StackOverflowQuestionsAndAnswers\DataGridNoBinding_47308996\SampleData.csv");
}
/// <summary>
/// This method will do what you want using a Data Driver instead of a StreamReader
/// Though, this method binds the whole DataTable to the DataGridView instead of manually creating 1 row per data row
/// </summary>
/// <param name="dataFilePath"></param>
private void AddToGridByBindingTheWholeTable(string dataFilePath)
{
dgv.AutoGenerateColumns = true;
string connstring = $"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={System.IO.Path.GetDirectoryName(dataFilePath)};Extended Properties=\"Text;HDR=NO;FMT=Delimited\"";
OleDbConnection conn = new OleDbConnection(connstring);
OleDbCommand command = new OleDbCommand($"select * from {System.IO.Path.GetFileName(dataFilePath)}", conn);
OleDbDataAdapter dataAdapter = new OleDbDataAdapter(command);
DataTable dt = new DataTable();
conn.Open();
dataAdapter.Fill(dt);
conn.Close();
dgv.DataSource = dt;
}
/// <summary>
/// This method will do what you want using a Data Driver instead of a StreamReader
/// In this method, we are actively creating 1 DataGridRow for each DataRow in the DataTable
/// </summary>
/// <param name="dataFilePath"></param>
private void AddToGridUsingDataDriver(string dataFilePath)
{
dgv.AutoGenerateColumns = false;
dgv.Columns.Add("Key", "Key");
dgv.Columns.Add("Value", "Value");
string connstring = $"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={System.IO.Path.GetDirectoryName(dataFilePath)};Extended Properties=\"Text;HDR=NO;FMT=Delimited\"";
OleDbConnection conn = new OleDbConnection(connstring);
OleDbCommand command = new OleDbCommand($"select * from {System.IO.Path.GetFileName(dataFilePath)}", conn);
OleDbDataAdapter dataAdapter = new OleDbDataAdapter(command);
DataTable dt = new DataTable();
conn.Open();
dataAdapter.Fill(dt);
conn.Close();
if (dt != null && dt.Rows.Count > 0)
{
foreach (DataRow item in dt.Rows)
{
int newrowid = dgv.Rows.Add();
dgv.Rows[newrowid].Cells[0].Value = item.Field<string>(0);
dgv.Rows[newrowid].Cells[1].Value = item.Field<string>(1);
}
}
dgv.Refresh();
}
/// <summary>
/// This method does not work. This emulates what you are currently doing.
/// </summary>
/// <param name="dgvdata"></param>
private void AddToGridNoWork(Dictionary<string, string> dgvdata)
{
dgv.AutoGenerateColumns = false;
dgv.Columns.Add("Key","Key");
dgv.Columns.Add("Value", "Value");
foreach (KeyValuePair<string, string> item in dgvdata)
{
dgv.Rows.Add();
dgv.Rows[dgv.Rows.Count - 1].Cells[0].Value = item.Key;
dgv.Rows[dgv.Rows.Count - 1].Cells[1].Value = item.Value;
dgv.Refresh();
}
}
/// <summary>
/// This method does work.
/// Add a new row to the Grid and store the new row index in rowindex
/// Then use the variable rowindex to update the correct row
/// </summary>
/// <param name="dgvdata"></param>
private void AddToGridDoesWork(Dictionary<string, string> dgvdata)
{
dgv.AutoGenerateColumns = false;
dgv.Columns.Add("Key", "Key");
dgv.Columns.Add("Value", "Value");
foreach (KeyValuePair<string, string> item in dgvdata)
{
int rowindex = dgv.Rows.Add();
dgv.Rows[rowindex].Cells[0].Value = item.Key;
dgv.Rows[rowindex].Cells[1].Value = item.Value;
}
}
}
}
At the moment I am using VB.Net.
I build my string, post it out and then parse the results.
Parsing Example for XML
Dim xml As New MWXMLDocument()
Dim sReason As String = "Unknown"
Try
xml.LoadXml(sresult)
If xml.SelectSimpleNode("AcceptedLead").InnerText = "true" Then
app.Outcome.RedirectURL = xml.SelectSimpleNode("result/redirecturl").InnerText
AcceptLead()
Return True
End If
sReason = xml.SelectSimpleNode("Reason").InnerText
Catch ex As Exception
sReason = "Error: " & ex.Message
End Try
DeclineLead(sReason)
Return False
End Function
How would I parse a result sent back in JSON, here is an example of the result I want to parse in using VB : Can i not just get the data from the string and parse as normal XML.
{"RedirectUrl":"www.test.com","Commission":5.0000,"Status":"accepted"}
You can use the JSON.NET Library
Example in C#:
var result = JsonConvert.DeserializeObject<RootObject>(string json);
The RootObject should be your own class.
You could use the .Net built in JavaScriptSerialiser
First add a reference to System.Web.Extensions and then
Imports System.Web.Script.Serialization
Followed by...
Dim sExampleJSON As String = "{""RedirectUrl"":""www.test.com"",""Commission"":5.0000,""Status"":""accepted""}"
Dim MySerializer As JavaScriptSerializer = New JavaScriptSerializer()
Dim MyDictionary As Dictionary(Of String, Object) = MySerializer.Deserialize(Of Dictionary(Of String, Object))(sExampleJSON)
If MyDictionary.ContainsKey("RedirectUrl") Then
Console.WriteLine(MyDictionary("RedirectUrl"))
End If
in global.asax.cs
using System.Data.Entity;
namespace RpManticSolAPI
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
}
}
}
The complete Answer
sResult = sResult.Replace("""", String.Empty)
If sResult.Contains("Status:accepted") Then
Dim parts = sResult.Replace("{", String.Empty).Replace("}", String.Empty).Split(",")
For i As Int16 = 0 To parts.Length - 1
If parts(i).StartsWith("RedirectUrl") Then
app.Outcome.RedirectURL = parts(i).Substring(12)
End If
If parts(i).StartsWith("Commission") Then
lendertier.LenderComm = CDec(parts(i).Substring(11))
End If
If parts(i).StartsWith("ApplicationRef") Then
app.Outcome.LenderReference = parts(i).Substring(15)
End If
Next
AcceptLead()
Return True
End If
If sResult.Contains("Reason:Duplicate") Then
sReason = "Duplicate"
ElseIf sResult.Contains("{Error:invalid credentials") Then
sReason = "Error: Invalid credentials"
ElseIf sResult.Contains("ValidationErrors:") Then
sReason = "Invalid call:" + sResult.Replace("ValidationErrors:", String.Empty).Replace(",Status:rejected", String.Empty)
Else
sReason = "Rejected"
End If
DeclineLead(sReason)
Return False
I have a HR web application which includes organization structure within workplaces.
The client is sending a .docx file with workplace name and its description. I need to make a C# application to get data from the .docx file and update some database tables with it.
I already tried .docx conversion to XML but I have no idea how to pick up data from that XML and insert it into the database.
Is there a easier way to update this database directly from a .docx file or what mechanics should I use to find data in the XML file.
Try this..
Below is the connection string to the database. You can modify it to suit yours
<connectionStrings>
<add name="conString" connectionString="Data Source=.\SQLEXPRESS;database=dbFiles; Integrated Security=true"/>
</connectionStrings >
To start with I have added a FileUpload control, a button and a Label to show messages
<asp:FileUpload ID="FileUpload1" runat="server" />
<asp:Button ID="btnUpload" runat="server" Text="Upload"
OnClick="btnUpload_Click" />
<br />
<asp:Label ID="lblMessage" runat="server" Text=""
Font-Names = "Arial"></asp:Label>
And here is the snippet which is called on the Upload Button Click event
C#
protected void btnUpload_Click(object sender, EventArgs e)
{
// Read the file and convert it to Byte Array
string filePath = FileUpload1.PostedFile.FileName;
string filename = Path.GetFileName(filePath);
string ext = Path.GetExtension(filename);
string contenttype = String.Empty;
//Set the contenttype based on File Extension
switch(ext)
{
case ".doc":
contenttype = "application/vnd.ms-word";
break;
case ".docx":
contenttype = "application/vnd.ms-word";
break;
case ".xls":
contenttype = "application/vnd.ms-excel";
break;
case ".xlsx":
contenttype = "application/vnd.ms-excel";
break;
case ".jpg":
contenttype = "image/jpg";
break;
case ".png":
contenttype = "image/png";
break;
case ".gif":
contenttype = "image/gif";
break;
case ".pdf":
contenttype = "application/pdf";
break;
}
if (contenttype != String.Empty)
{
Stream fs = FileUpload1.PostedFile.InputStream;
BinaryReader br = new BinaryReader(fs);
Byte[] bytes = br.ReadBytes((Int32)fs.Length);
//insert the file into database
string strQuery = "insert into tblFiles(Name, ContentType, Data)" +
" values (#Name, #ContentType, #Data)";
SqlCommand cmd = new SqlCommand(strQuery);
cmd.Parameters.Add("#Name", SqlDbType.VarChar).Value = filename;
cmd.Parameters.Add("#ContentType", SqlDbType.VarChar).Value
= contenttype;
cmd.Parameters.Add("#Data", SqlDbType.Binary).Value = bytes;
InsertUpdateData(cmd);
lblMessage.ForeColor = System.Drawing.Color.Green;
lblMessage.Text = "File Uploaded Successfully";
}
else
{
lblMessage.ForeColor = System.Drawing.Color.Red;
lblMessage.Text = "File format not recognised." +
" Upload Image/Word/PDF/Excel formats";
}
}
VB.Net
Protected Sub btnUpload_Click(ByVal sender As Object, ByVal e As EventArgs)
' Read the file and convert it to Byte Array
Dim filePath As String = FileUpload1.PostedFile.FileName
Dim filename As String = Path.GetFileName(filePath)
Dim ext As String = Path.GetExtension(filename)
Dim contenttype As String = String.Empty
'Set the contenttype based on File Extension
Select Case ext
Case ".doc"
contenttype = "application/vnd.ms-word"
Exit Select
Case ".docx"
contenttype = "application/vnd.ms-word"
Exit Select
Case ".xls"
contenttype = "application/vnd.ms-excel"
Exit Select
Case ".xlsx"
contenttype = "application/vnd.ms-excel"
Exit Select
Case ".jpg"
contenttype = "image/jpg"
Exit Select
Case ".png"
contenttype = "image/png"
Exit Select
Case ".gif"
contenttype = "image/gif"
Exit Select
Case ".pdf"
contenttype = "application/pdf"
Exit Select
End Select
If contenttype <> String.Empty Then
Dim fs As Stream = FileUpload1.PostedFile.InputStream
Dim br As New BinaryReader(fs)
Dim bytes As Byte() = br.ReadBytes(fs.Length)
'insert the file into database
Dim strQuery As String = "insert into tblFiles" _
& "(Name, ContentType, Data)" _
& " values (#Name, #ContentType, #Data)"
Dim cmd As New SqlCommand(strQuery)
cmd.Parameters.Add("#Name", SqlDbType.VarChar).Value = filename
cmd.Parameters.Add("#ContentType", SqlDbType.VarChar).Value _
= contenttype
cmd.Parameters.Add("#Data", SqlDbType.Binary).Value = bytes
InsertUpdateData(cmd)
lblMessage.ForeColor = System.Drawing.Color.Green
lblMessage.Text = "File Uploaded Successfully"
Else
lblMessage.ForeColor = System.Drawing.Color.Red
lblMessage.Text = "File format not recognised." _
& " Upload Image/Word/PDF/Excel formats"
End If
End Sub
The above code simply reads the uploaded File as Stream and then converts the Stream to Byte array using Binary Reader and then the finally the byte arrays is saved to the database InsertUpdateData method executes the query to save the data in database
The InsertUpdateData function is given below
C#
private Boolean InsertUpdateData(SqlCommand cmd)
{
String strConnString = System.Configuration.ConfigurationManager
.ConnectionStrings["conString"].ConnectionString;
SqlConnection con = new SqlConnection(strConnString);
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
try
{
con.Open();
cmd.ExecuteNonQuery();
return true;
}
catch (Exception ex)
{
Response.Write(ex.Message);
return false;
}
finally
{
con.Close();
con.Dispose();
}
}
I have a spreadsheet that is updated by another server (out of my control) and I need to automate bringing that data into SQL 2005. The data is always the first page of the spreadsheet. However, the name of that sheet changes depending on the number of rows.
Is there a way to run an SSIS job that pulls in data from Excel without knowing the sheetname beforehand? It seems to rely on the sheet name as the data source, but I'm looking to tell it "sheet number 1" or something similar.
I would script out the Worksheet name to a SSIS User Variable. If you are not opposed to inserting a script task into your SSIS package try this: (Based on link text )
Excel.Application xlApp = new Excel.ApplicationClass();
Excel.Workbook xlWorkBook = xlApp.Workbooks.Open("<Name of your excel app>.xls", 0, xlWorkBook true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
// Look up worksheet by index
Excel.Worksheet xlWorkSheet =(Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
user::worksheetname = xlWorkSheet.Name;
/* Do clean up. Working with COM object */
Just for the record, I'm using this code in Script Task to solve the problem. Variables used are: Filename, SheetName.
Note that my Excel filename is dynamic.
// GET NAME OF FIRST SHEET
string filename = (string)Dts.Variables["Filename"].Value;
string sheetName = null;
string connStr =
String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=\"EXCEL 8.0;IMEX=1;\"", filename);
var conn = new OleDbConnection(connStr);
try
{
conn.Open();
using(var dtSheet = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null))
{
var row0 = dtSheet.Rows[0];
sheetName = row0["TABLE_NAME"].ToString();
}
}
catch (Exception)
{
throw;
}
finally
{
conn.Close();
conn.Dispose();
}
if (!String.IsNullOrEmpty(sheetName))
{
Dts.Variables["SheetName"].Value = sheetName;
Dts.Events.FireInformation(1, "User::SheetName", sheetName, "", 0, ref dummy);
Dts.TaskResult = (int)ScriptResults.Success;
}
else
{
Dts.Events.FireError(0, "User::SheetName", "No SheetName found!", String.Empty, 0);
Dts.TaskResult = (int)ScriptResults.Failure;
}
I had a similar problem. The solution that I implemented was first read the excel file using OleDB connection. Open the connection and then retrieve all the sheet names. Here is an example
Dim strConnectionString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\ABC.xls;Extended Properties=""EXCEL 8.0;"""
Dim lstSheetName As List(Of String) = Nothing
Try
objConn = New OleDbConnection(Me.ConnectionString)
objConn.Open()
lstSheetName = New List(Of String)
Using dtSheetTable As DataTable = objConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables,Nothing)
For Each drRow As DataRow In dtSheetTable.Rows
lstSheetName.Add("[" & drRow("TABLE_NAME").ToString().Replace("'", "''") & "]")
Next
End Using
Catch ex as Exception
Throw
Finally
If objConn.State = ConnectionState.Open Then objConn.Close()
objConn.Dispose()
End Try
This all code is written ASPX.VB and then I am executing the SSIS package through code behind and passing the first value in the lstSheetName variable (lstSheetName(0).ToString())
This was
If anyone has trouble with the JET Driver you can use the AccessDatabase drivers now. This was adapted from above and is verified working on my machine, no extra references are needed for this.
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.Data.OleDb;
public void Main()
{
// GET NAME OF FIRST SHEET
string filename = Dts.Variables["User::ActiveFileName"].Value.ToString();
string sheetName = null;
bool dummy = true;
string connStr =
String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"EXCEL 12.0 XML;HDR=YES\";", filename);
var conn = new OleDbConnection(connStr);
try
{
conn.Open();
using(var dtSheet = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null))
{
var row0 = dtSheet.Rows[0];
sheetName = row0["TABLE_NAME"].ToString();
}
if (!String.IsNullOrEmpty(sheetName))
{
Dts.Variables["SheetName"].Value = sheetName;
Dts.Events.FireInformation(1, "User::SheetName", sheetName, "", 0, ref dummy);
Dts.TaskResult = (int)ScriptResults.Success;
}
else
{
throw new Exception("No SheetName found!");
}
}
catch (Exception ex)
{
Dts.Events.FireError(0, "User::SheetName", ex.Message, String.Empty, 0);
Dts.TaskResult = (int)ScriptResults.Failure;
}
finally
{
conn.Close();
conn.Dispose();
}
}
I don't think so...I don't know of any ordinal reference syntax, e.g., Sheets[0] that you could use.
So if you can't get the data without knowing the sheet name - you just need to dynamically find out the sheet name. This link on getting Excel schema info in SSIS should help you do that. Once you have that, you can pass the sheet name in as a variable, and away you go.
I have had this same issue myself in the past and was unable to find a solution to having an Excel file be read in which has its sheet name change from file to file.
My guess, which I was unable to get to work, would be to use expressions in the properties of the data connection. You would need to somehow read the sheet name into a variable, then use that variable's result in the sheet name for the data connection.
Best of luck to you, and sorry I couldn't be of more help.
I am using ASP.NET to read the data in the excel file. I am using a file upload control to read the file. I am able to read the data from the file in my local machine, but after deploying my code in the server, when I try to read the file from the client machine, I am getting an exception.
FileUpload1.PostedFile.FileName is throwing the exception in the server.
The exception message is:
'D:\path in client machine\MyExcel.xls' could not be found. Check the spelling of the file name, and verify that the file location is correct. If you are trying to open the file from your list of most recently used files on the File menu, make sure that the file has not been renamed, moved, or deleted.
Please help.
Code :
<add key="OleDbConnection" value="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=
FilePath ;Extended Properties="Excel 8.0;HDR=Yes;IMEX=1""/>
string OleDbConnection =
ConfigurationManager.AppSettings["OleDbConnection"].ToString().Replace("FilePath",
fileUpload.PostedFile.FileName).Trim();
Excel.ApplicationClass xlApp = new Excel.ApplicationClass();
Excel.Workbooks xlWorkBooks = (Excel.Workbooks)xlApp.Workbooks;
Excel.Workbook wb = xlWorkBooks._Open(fileUpload.PostedFile.FileName, Type.Missing,
false, Type.Missing, "", "", true, Excel.XlPlatform.xlWindows, "\t", true,
false, Type.Missing, true);
string strSheetName = ((Excel.Worksheet)wb.Sheets[1]).Name.ToString();
xlWorkBooks.Close();
xlApp.Quit();
oledbCommand = new OleDbCommand();
oledbAdapter = new OleDbDataAdapter();
DataSet dsExcellData = new DataSet();
oledbConnection = new OleDbConnection(OleDbConnection);
oledbConnection.Open();
oledbCommand.Connection = oledbConnection;
oledbCommand.CommandText = "Select * from [" + strSheetName + "$]";
oledbAdapter.SelectCommand = oledbCommand;
oledbAdapter.Fill(dsExcellData);
return dsExcellData
Hi I am posting the sample code that i am having
Add a fie upload control and a button.On the button click execute the below code after selecting the file from the client machine.
string OleDbConnection = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source= \"FilePath\";Extended Properties=\"Excel 8.0;HDR=Yes;IMEX=1\"";
OleDbConnection = OleDbConnection.Replace("FilePath", FileUpload1.PostedFile.FileName);
Label6.Text = OleDbConnection;
string strSheetName = "ASSET_RECV";
OleDbConnection oledbConnection;
OleDbCommand oledbCommand;
OleDbDataAdapter oledbAdapter;
oledbCommand = new OleDbCommand();
oledbAdapter = new OleDbDataAdapter();
DataSet dsExcellData = new DataSet();
oledbConnection = new OleDbConnection(OleDbConnection);
oledbConnection.Open();
oledbCommand.Connection = oledbConnection;
//oledbCommand.CommandText = "Select * from [{0}$]";
oledbCommand.CommandText = "Select * from [" + strSheetName + "$]"; // i want to find this sheet name
oledbAdapter.SelectCommand = oledbCommand;
oledbAdapter.Fill(dsExcellData);
oledbConnection.Close();
GridView1.DataSource = dsExcellData.Tables[0];
GridView1.DataBind();
1) Publish the project in IIS.Try to run the application from another machine and read the data from the excel file (from client machine).
you will get the below error .Please help.
The Microsoft Jet database engine could not find the object 'D:\FileName.xls'. Make sure the object exists and that you spell its name and the path name correctly.
I think you need to save the file before you can open it. You can use:
PostedFile.SaveAs()
to save it to the server.
Did that help?
Can you post your uploading code?
Should be something like this..
<asp:FileUpload ID="batchUpload" runat="server" />
<asp:Button runat="server" ID="uploadButton" Text="Upload" OnClick="UploadButton_Click" />
protected void UploadButton_Click(object sender, EventArgs e)
{
// Server time out 50 mins..
Context.Server.ScriptTimeout = 60 * 50;
errorLabel.Style[HtmlTextWriterStyle.Color] = "Red";
if (batchUpload.PostedFile == null || batchUpload.PostedFile.ContentLength == 0) {
errorLabel.InnerText = "Enter a valid file";
uploadButton.Enabled = true;
return;
}
string path = XMAppSettings.UploadsPath;
filePath = Path.Combine(path, batchUpload.FileName);
try {
batchUpload.SaveAs(filePath);
} catch (HttpException exception) {
errorLabel.InnerText = "Fatal error";
exception.Log();
return;
}
Notice the batchUpload.SaveAs(filePath)
Confirm the save!
Also, since you are trying to extract data from an excel sheet I'd suggest you exploit Linq over datasets(if you are not planning to do inserts). Excel.ApplicationClass will require that you reference the excel interops
/// <summary>
/// Summary description for ExcelHelper.
/// </summary>
internal sealed class ExcelHelper
{
private const string CONNECTION_STRING = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=<FILENAME>;Extended Properties=\"Excel 8.0;HDR=Yes;\";";
public static DataTable GetDataTableFromExcelFile(string fullFileName, ref string sheetName)
{
OleDbConnection objConnection = new OleDbConnection(CONNECTION_STRING.Replace("<FILENAME>", fullFileName));
DataSet dsImport = new DataSet();
try {
objConnection.Open();
DataTable dtSchema = objConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if ((null == dtSchema) || (dtSchema.Rows.Count <= 0)) {
throw new ArgumentNullException("No sheets");
}
//Reading the first sheet name from the Excel file.
sheetName = dtSchema.Rows[0]["TABLE_NAME"].ToString();
new OleDbDataAdapter("SELECT * FROM [" + sheetName + "]", objConnection).Fill(dsImport);
} catch (Exception e) {
e.Log();
throw;
} finally {
objConnection.Close();
objConnection.Dispose();
}
return dsImport.Tables[0];
}
}
and then do stuff like
var table = ExcelHelper.GetDataTableFromExcelFile(fileName, ref something).AsEnumerable();
var rollnoList = table
.Where(x => !String.IsNullOrEmpty(x.Field<string>("Roll Number")))
.Select(x => ExtractUser(x));
You need to make sure the file exists where you say it does. The error is saying it cannot find the file specified by the path. Also make sure your spelling is correct.
Thanks for the replies.I have fixed the issue.
The mistake that i did was i supplied the FileUpload1.PostedFile.FileName as a path to the excel connection string.What happens when we deploy the code in the server and try to read the excell is ,it is searching for the file in the server path.
So we need to save the file to the server before reading the file and we need to pass that server path to the excel connection string.
After reading the data from the excel you can delete the file.
But i am not sure whether there are some other work around like passing the file object as the datasource for the excel connection string.