Import data from Excel using SSIS without knowing sheet name - sql

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.

Related

Output the System.Object variable value to a flat file in SSIS

I am sorry if this question is a repeat. I have a system.object variable where I store results for a select query. I need to output the results to a flat file to further process it. I have the following piece of code that works for couple of seconds and then throws the system invocation error. Can you please suggest any edits to this or if I am doing something wrong:
Public Sub Main()
Dim x As New OleDb.OleDbDataAdapter
Dim dt As New DataTable
Dim str As String = vbNullString
If System.IO.File.Exists("D:\BKP\AD.txt") = False Then
System.IO.File.Create("D:\BKP\AD.txt")
End If
'MessageBox.Show("Hello")
Dim i As Int32
x.Fill(dt, Dts.Variables("User::LDAPResultSet").Value)
i = dt.Rows.Count
For j As Int32 = 0 To i - 1
str = str & Join(dt.Rows.Item(j).ItemArray(), ",") & vbCrLf
Next
Dim objWriter As New System.IO.StreamWriter("D:\BKP\AD.txt")
objWriter.Write(str)
objWriter.Close()
End Sub
End Class
Is there a better way to write this or if there's an alternative code piece I'd like to try that as well. Thank you for your time.
The points from my comment:
You don't need to create the file: the StreamWriter will do that if required, otherwise it will overwrite an existing file.
String.Join(separator, values) - you have the separator as the second argument.
You should also call objWriter.Dispose() when you've finished using it.
But:
A StringBuilder is more efficient for creating a large string.
You can write all the text in one go by using the File.WriteAllText method.
Sub Main()
Dim outputFile As String = "D:\BKP\AD.txt"
Dim x As New OleDb.OleDbDataAdapter
Dim dt As New DataTable
Dim sb As New Text.StringBuilder
x.Fill(dt, Dts.Variables("User::LDAPResultSet").Value)
For j As Integer = 0 To dt.Rows.Count - 1
sb.AppendLine(String.Join(",", dt.Rows.Item(j).ItemArray()))
Next
IO.File.WriteAllText(outputFile, sb.ToString())
End Sub
I guess that you left some lines to do with the OleDbDataAdapter out, but I am not familiar with SSIS.
If you can, use Option Strict On - it would have pointed out the problem with the String.Join for you.
I have done it this way in the past:
https://www.timmitchell.net/post/2015/04/20/using-the-ssis-object-variable-as-a-data-flow-source/
Basically pass the variable into a Script Transformation and then add data to the pipeline. From that point you can use a destination component as normal and avoid creating the output file and delimiting the fields.
#region Namespaces
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
#endregion
// Add in the appropriate namespaces
using System.Data;
using System.Data.OleDb;
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
public override void CreateNewOutputRows()
{
// Set up the DataAdapter to extract the data, and the DataTable object to capture those results
OleDbDataAdapter da = new OleDbDataAdapter();
DataTable dt = new DataTable();
// Extract the data from the object variable into the table
da.Fill(dt, Variables.vResults);
// Since we know the column metadata at design time, we simply need to iterate over each row in
// the DataTable, creating a new row in our Data Flow buffer for each
foreach (DataRow dr in dt.Rows)
{
// Create a new, empty row in the output buffer
SalesOutputBuffer.AddRow();
// Now populate the columns
SalesOutputBuffer.SalesOrderID = int.Parse(dr["SalesOrderID"].ToString());
SalesOutputBuffer.RevisionNumber = int.Parse(dr["RevisionNumber"].ToString());
SalesOutputBuffer.OrderDate = DateTime.Parse(dr["OrderDate"].ToString());
SalesOutputBuffer.ShipDate = DateTime.Parse(dr["ShipDate"].ToString());
SalesOutputBuffer.Status = int.Parse(dr["Status"].ToString());
SalesOutputBuffer.TotalDue = decimal.Parse(dr["TotalDue"].ToString());
}
}
}
This is what worked for me finally:
public override void CreateNewOutputRows()
{
// Set up the DataAdapter to extract the data, and the DataTable object to capture those results
OleDbDataAdapter da = new OleDbDataAdapter();
DataTable dt = new DataTable();
// Extract the data from the object variable into the table
da.Fill(dt, Variables.LDAPResultSet);
// Since we know the column metadata at design time, we simply need to iterate over each row in
// the DataTable, creating a new row in our Data Flow buffer for each
foreach (DataRow dr in dt.Rows)
//'foreach (DataColumn col in dt.Columns)
{
{
// Create a new, empty row in the output buffer
LDAPOutputBuffer.AddRow();
object[] array = dr.ItemArray;
LDAPOutputBuffer.ADENTName = array[1].ToString();
LDAPOutputBuffer.DisplayName = array[3].ToString();
LDAPOutputBuffer.DNName = array[2].ToString();
LDAPOutputBuffer.Mail = array[0].ToString();
}
}
}
}

Prompting Database Login when loading crystal reports

I've got a problem every time i load my report on crystal. Always asking for database login but when i enter my password(which is the password of my connection) it always says that login failed.
This is my code:
Dim _ReportLogonInfos As New TableLogOnInfos
Dim _ReportLogonInfo As New TableLogOnInfo
Dim _ReportConInfo As New ConnectionInfo
Dim _Tables As Tables
Dim _Table As Table
With _ReportConInfo
.ServerName = "localhost"
.DatabaseName = "database"
.UserID = "root"
.Password = "Qwerty123"
End With
Dim _Report As New rptPrntIss
_Tables = _Report.Database.Tables
For Each _Table In _Tables
_ReportLogonInfo = _Table.LogOnInfo
_ReportLogonInfo.ConnectionInfo = _ReportConInfo
_Table.ApplyLogOnInfo(_ReportLogonInfo)
Next
CrystalReportViewer1.ReportSource = _Report
In addition to what you set, I also set the following (sorry this is in C# not VB.NET - hopefully you can translate):
1
//SET DATASOURCE FOR EACH SUBREPORT IN REPORT
foreach (CrystalDecisions.CrystalReports.Engine.Section section in CrystalReportSource2.ReportDocument.ReportDefinition.Sections)
{
// In each section we need to loop through all the reporting objects
foreach (CrystalDecisions.CrystalReports.Engine.ReportObject reportObject in section.ReportObjects)
{
if (reportObject.Kind == ReportObjectKind.SubreportObject)
{
SubreportObject subReport = (SubreportObject)reportObject;
ReportDocument subDocument = subReport.OpenSubreport(subReport.SubreportName);
foreach (CrystalDecisions.CrystalReports.Engine.Table table in subDocument.Database.Tables)
{
// Cache the logon info block
TableLogOnInfo logOnInfo = table.LogOnInfo;
// Set the connection
logOnInfo.ConnectionInfo = crConnectionInfo;
// Apply the connection to the table!
table.ApplyLogOnInfo(logOnInfo);
}
}
}
}
2
if (CrystalReportSource2.ReportDocument.DataSourceConnections.Count > 0)
CrystalReportSource2.ReportDocument.DataSourceConnections[0].SetConnection(server, db, crystalUser, pwd);
3
CrystalReportSource2.ReportDocument.SetDatabaseLogon(crystalUser, pwd, server, db);

lotuscript: some questions about connecting to a SQL DB

I've got this code that is working... I read from an MS SQL database some rows from a table and then send an email for each row.
I'm about to add an "attachment" field, on my SQL database and I'd like to add the attachment at the end of my body.
I have two questions: 1) what datatype should I use on MS SQL? (Binary field, maybe) and 2) if someone else has some example code, I'd really appreciate it.
A bonus question: on a more advanced version of this script, i first run by all my results from my resultset to get the IDs from the messages and then update their status on the MS SQL table.
Then I try and run by the same resultset again, to actually perform the sending....
Somehow, on the second run, I'm having trouble starting from row 1, using the same code than bellow... any advice on what's the best way to do that?: My requirement is that I have to run twice by the same resultset. :)
Thanks in advance.
Option Public
Uselsx "*LSXODBC"
Sub Initialize
Dim session As New NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim subject As String, cc As String, bcc As String, sender As String, OID As String, mailto As String, bodyNotMIME As String
Dim body As NotesMIMEEntity
On Error Goto errorCounter
Set db = session.CurrentDatabase
Gosub SendMailGeneral
Exit Sub
SendMailGeneral:
Dim con As New ODBCConnection
Dim qry As New ODBCQuery
Dim result As New ODBCResultSet
Dim defaultQuery As String
Set qry.Connection = con
con.SilentMode = True
If con.ConnectTo("DSN_Name","USER_NAME", "PASSWORD") Then
Set result.Query = qry
defaultQuery = "select TOP (10) * from Message where StatusType=0"
qry.SQL = defaultQuery
result.Execute
If (result.IsResultSetAvailable) Then
Do
result.NextRow
Gosub GetRowFields
Gosub SendMail
Loop Until result.IsEndOfData
End If
End If
result.Close(DB_CLOSE)
Return
End Sub
GetRowFields:
mailto = result.GetValue("To")
cc = result.GetValue("CC")
bcc = result.GetValue("Bcc")
sender = result.GetValue("Sender")
subject = result.GetValue("Subject")
bodyNotMIME = result.GetValue("Body")
OID = result.GetValue("OID")
Return
SendMail:
Dim mail As NotesDocument
Set mail = New NotesDocument(db)
Dim stream As NotesStream
Set stream = session.CreateStream
'Recipients
mail.SendTo = mailto
mail.CopyTo = cc
mail.BlindCopyTo = bcc
' Set all sender-related fields
mail.ReplyTo = sender
mail.Principal = sender
mail.From = sender
mail.AltFrom = sender
mail.SendFrom = sender
mail.INetFrom = sender
mail.tmpDisplaySentBy = sender
mail.tmpDisplayFrom_Preview = sender
mail.DisplaySent = sender
'Body
Call stream.WriteText(bodyNotMIME)
Set body = mail.CreateMIMEEntity
Call body.SetContentFromText _
(stream, "text/html; charser=iso-8859-1", ENC_NONE)
'Subject
mail.Subject = subject
'Send
Call mail.Send(False, False)
Return
Wasn't this line:
result.NextRowcode
supposed to be:
result.NextRow
?
I don't know about MSSQL, but in DB2 we routinely use Blob/Clob binary data type to store any type of files.
I hear that many MSSQL experts recommend rather storing files on file system with only their path and file name in a DB.
OK, here's the abbreviated code from my Java ScriptLibrary that uses JDBC to connect to DB2 and execute a query (you would only need to import your db's jar-s and use com.microsoft.sqlserver.jdbc.SQLServerDriver for MS SQL):
import java.sql.*;
import com.ibm.db2.jcc.DB2Driver;
public class DB2Connection {
protected String server;
protected String port;
protected String dbName;
protected String userdb2;
protected String pwddb2;
protected java.sql.Connection con;
public DB2Connection( String srv, String port, String db, String user, String pass ){
this.server = srv;
this.port = port;
this.dbName = db;
this.userdb2 = user;
this.pwddb2 = pass;
connectDB2();
}
public void connectDB2() {
try {
Class.forName("com.ibm.db2.jcc.DB2Driver"); // .newInstance();
String url = "jdbc:db2://" + server + ":" + port + "/" + dbName;
con = DriverManager.getConnection(url, userdb2, pwddb2);
System.out.println("Connection to DB2 succeded");
} catch (Exception e) {
System.out.println("Error connecting DB2 Server") ;
e.printStackTrace();
}
}
protected ResultSet executeQuery( String queryString ) throws SQLException, Exception {
System.out.println( "Preparing query:\t" + queryString );
ResultSet rs = null;
try {
Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
rs = stmt.executeQuery(queryString);
} catch (SQLException sqle) {
String error = ("SQLException : Could not execute query");
throw new SQLException(error);
} catch (Exception e) {
String error1 = ("Exception : An Unknown error occurred.");
throw new Exception(error1);
}
return rs;
}
protected int executeCountQuery( StringBuffer queryStr ){
System.out.println( "Preparing query:\t" + queryStr );
try {
ResultSet rs = executeQuery( queryStr.toString( ) );
rs.next(); //only one row in result set
return rs.getInt(1);
} catch (SQLException sqle) {
System.out.println("SQLException: Could not get ResultSet from DB2Connection.executeQuery");
sqle.printStackTrace();
} catch (Exception e) {
System.out.println("Exception : An Unknown error occurred while calling.");
e.printStackTrace();
}
return 0;
}
protected int executeCountQuery( PreparedStatement ps ){
//System.out.println( "Preparing prepared statement - query:\t" ); //+ ps.getQuery( ) );
try {
ResultSet rs = ps.executeQuery( );
rs.next(); //only one row in result set
return rs.getInt(1);
} catch (SQLException sqle) {
System.out.println("SQLException: Could not get ResultSet from DB2Connection.executeQuery");
sqle.printStackTrace();
} catch (Exception e) {
System.out.println("Exception : An Unknown error occurred while calling.");
e.printStackTrace();
}
return 0;
}
public Connection getConnection(){
return con;
}
}
To check out the examples of using LS2J to use Java classes directly from your LotusScript code, download this great LS2J samples database from Julian Robichaux:
http://www.nsftools.com/tips/NotesTips.htm#ls2jexamples
And here's a good link to start with, explains how to use JDBC with MS SQL server:
http://support.microsoft.com/kb/313100

How do i change logon info dynamically in crystal report and ms access?

I have my crystal reports file accessing data from msaccess database.
now while loading report i need to pass the logon info of the msaccess database along with the database name from vb.net.
I tried using
Dim ConnInfo As ConnectionInfo = New ConnectionInfo()
CRpt.ReportOptions.EnableSaveDataWithReport = False
ConnInfo.IntegratedSecurity = False
ConnInfo.ServerName = ""
ConnInfo.UserID = ""
ConnInfo.Password = ""
ConnInfo.DatabaseName = OLEDBLayer.GetDBLocation()
ConnInfo.Type = ConnectionInfoType.DBFile
'CCINFo.ServerName =
For Each CTable As Table In CRpt.Database.Tables
CTableLogInfo = CTable.LogOnInfo
CTableLogInfo.ConnectionInfo = ConnInfo
'CTable.Location = OLEDBLayer.GetDBLocation
CTable.ApplyLogOnInfo(CTableLogInfo)
Next
But not working. What am i missing?
You can use the following code to apply certain connection details for a report at run time.
Sorry, code in c#.
Please use that method just after loading report rpt file, and before printing/exporting/viewing it.
public static void CrystalReportLogOn(ReportDocument reportParameters,
string serverName,
string databaseName,
string userName,
string password)
{
TableLogOnInfo logOnInfo;
ReportDocument subRd;
Sections sects;
ReportObjects ros;
SubreportObject sro;
if (reportParameters == null)
{
throw new ArgumentNullException("reportParameters");
}
try
{
foreach (CrystalDecisions.CrystalReports.Engine.Table t in reportParameters.Database.Tables)
{
logOnInfo = t.LogOnInfo;
logOnInfo.ReportName = reportParameters.Name;
logOnInfo.ConnectionInfo.ServerName = serverName;
logOnInfo.ConnectionInfo.DatabaseName = databaseName;
logOnInfo.ConnectionInfo.UserID = userName;
logOnInfo.ConnectionInfo.Password = password;
logOnInfo.TableName = t.Name;
t.ApplyLogOnInfo(logOnInfo);
t.Location = t.Name;
}
}
catch
{
throw;
}
sects = reportParameters.ReportDefinition.Sections;
foreach (Section sect in sects)
{
ros = sect.ReportObjects;
foreach (ReportObject ro in ros)
{
if (ro.Kind == ReportObjectKind.SubreportObject)
{
sro = (SubreportObject)ro;
subRd = sro.OpenSubreport(sro.SubreportName);
try
{
foreach (CrystalDecisions.CrystalReports.Engine.Table t in subRd.Database.Tables)
{
logOnInfo = t.LogOnInfo;
logOnInfo.ReportName = reportParameters.Name;
logOnInfo.ConnectionInfo.ServerName = serverName;
logOnInfo.ConnectionInfo.DatabaseName = databaseName;
logOnInfo.ConnectionInfo.UserID = userName;
logOnInfo.ConnectionInfo.Password = password;
logOnInfo.TableName = t.Name;
t.ApplyLogOnInfo(logOnInfo);
}
}
catch
{
throw;
}
}
}
}
}
I searched alot and finally after testing my self by creating new report using static data i got the solution for dynamic one.
My test Procedure:
1.) Created new Crystal Report file:
2.) Created new Database Connection to the .accdb access 2007 file
3.) Created new Form
4.) Added Crystal Report Viewer control on the form
5.) Assigned the report document to the previously created report.
6.) set break point on load of the form
7.) Read all the settings
8.) Copied the settings of the report document, document tables logon info.
9.) Pasted the settings read to my project.
10.) Worked fine... :)
My Code :
//here crpt is a sample report document
Dim CTableLogInfo As TableLogOnInfo
Dim ConnInfo As CrystalDecisions.Shared.ConnectionInfo = New ConnectionInfo()
ConnInfo.Type = ConnectionInfoType.CRQE
ConnInfo.ServerName = DBLayer.GetAbsoluteDBPath()
ConnInfo.DatabaseName = ""
ConnInfo.UserID = "Admin"
ConnInfo.AllowCustomConnection = False
ConnInfo.IntegratedSecurity = False
For Each CTable As Table In CRpt.Database.Tables
CTable.LogOnInfo.ConnectionInfo = ConnInfo
CTableLogInfo = CTable.LogOnInfo
CTableLogInfo.ReportName = CRpt.Name
CTableLogInfo.TableName = CTable.Name
CTable.ApplyLogOnInfo(CTableLogInfo)
Next
CrystalReportViewer1.ReportSource = CRpt
CrystalReportViewer1.RefreshReport()
I got the point that setting the database path to the servername would resolve that
Try this out:
Dim CTableLogInfo As TableLogOnInfo
Dim ConnInfo As CrystalDecisions.Shared.ConnectionInfo = New ConnectionInfo()
Dim CRpt As New ReportDocument
String filename = "rptSales.rpt"
ConnInfo.Type = ConnectionInfoType.CRQE
ConnInfo.ServerName = AppSettings("server")
ConnInfo.DatabaseName = AppSettings("dbNm")
ConnInfo.UserID = AppSettings("username")
ConnInfo.Password = AppSettings("pas")
ConnInfo.AllowCustomConnection = False
ConnInfo.IntegratedSecurity = False
CRpt.Load(AppSettings("reppath") & filename)
For Each CTable As Table In CRpt.Database.Tables
CTable.LogOnInfo.ConnectionInfo = ConnInfo
CTableLogInfo = CTable.LogOnInfo
CTableLogInfo.ReportName = CRpt.Name
CTableLogInfo.TableName = CTable.Name
CTable.ApplCTableLogInfo)
Next

FileUpload1.PostedFile.FileName is throwing exception

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.