Disclaimer: I know this is a bad way to do things. It is the only option we have with our client.
Problem:
We need to read data from an Excel file every x amount of time. The data is constantly changing via a 3rd party Excel plug in. The environment for the application is Windows XP, SP1 and .Net 2.0. No upgrading the OS to SP2/3 or upgrading the .Net Framework. Again, this is all per customer parameters.
Here is current code we have:
String sConnectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Settings.ReutersFilePath + ";Extended Properties=\"Excel 8.0;HDR=No;IMEX=1\"";
using (OleDbConnection objConn = new OleDbConnection(sConnectionString))
{
try
{
objConn.Open();
_dataSet = new DataSet();
OleDbCommand objCmdSelect = new OleDbCommand("SELECT * FROM [" + ConfigurationManager.AppSettings["Excel.WorksheetName"] + "$]", objConn);
OleDbDataAdapter objAdapter1 = new OleDbDataAdapter();
objAdapter1.SelectCommand = objCmdSelect;
objAdapter1.Fill(_dataSet);
_dataTable = _dataSet.Tables[0];
objConn.Close();
// Persists new data to a database.
UpdateSQL();
}
catch (Exception ex) { }
finally
{
_isCurrentlyProcessing = false;
if (objConn != null && (objConn.State != ConnectionState.Broken || objConn.State != ConnectionState.Closed))
{
objConn.Close();
}
}
}
This code works when running from console or a Windows form, but when we run it from a Windows service, it cannot access the Excel file. Is there a limitation in XP w/SP1 that doesn't allow interaction with desktop applications like there is in Vista? Can this be done from a service? The reliability of running this from a service is much needed from the client.
Edit:
The service is running as LocalSystem.
Edit #2:
The error I get when running from a service is: The Microsoft Jet database engine cannot open the file ''. It is already opened exclusively by another user, or you need permission to view its data.
The Excel file IS open on the desktop, but it has to be open for it to get updates from the 3rd party application.
In addition to #sontek's answer.
[only applicable If you are the owners/developers of the Spreadsheet in question...]
You may find it easier to work with a "data push" model rather than a "data pull" model. It's usually an easier programming model to push the data via an excel macro directly into your data store, based upon some event from your plug-in. this is often a much better scenario than a service polling on a timer.
Excel doesn't allow you to open a file simultaneously. You need to either create it as a shared workbook or make a copy of the file and work off of the copy.
There is also full excel API (Microsoft.Office.Interop.Excel) that you could try using, which would allow you to hook into the currently opened excel/workbook.
What user is the service running as? Make sure that user has access to the specific file.
It seems most likely that it is a permissions issue. Windows services run under a different user account than desktop applications.
Also, you mention that you are executing this method every x amount of time. Make sure you are using the right timers. http://www.aspfree.com/c/a/C-Sharp/Timer-Objects-in-Windows-Services-with-C-sharp-dot-NET/
And you should be able to attach a debugger to the service by using "Attach to Process" and selecting your host process. This might give you more info on your problem. http://msdn.microsoft.com/en-us/library/7a50syb3(VS.80).aspx
SpreadsheetGear for .NET can open a file even if Excel currently has the file open and it is well suited to using from a Windows Service.
However, the file on disk will not reflect changes which have not been saved by Excel, and SpreadsheetGear would not be able to open a workbook while Excel is in the middle of saving, so the service would have to take that into account.
Disclaimer: I own SpreadsheetGear LLC
You could try making it a shared workbook (Tools > Share Workbook). This lets multiple users edit the same workbook concurrently. I'm not sure if that would work for you as some workbook features get locked down when it is shared
Related
I have asp.net application which loads excel file to read. It works fine on my local development server. However when I upload it to server it wont display the uploaded excel file.
I have MS Office installed on my local machine but not on server.
Thanks for your guidance
The code I am using is...
if (fileExtension == ".xls")
{
connectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + fileLocation + ";Extended Properties=\"Excel 8.0;HDR=Yes;IMEX=2\"";
}
else if (fileExtension == ".xlsx")
{
connectionString = "Provider=Microsoft.ACE.OLEDB.14.0;Data Source=" + fileLocation + ";Extended Properties=\"Excel 14.0;HDR=Yes;IMEX=2\"";
}
//Create OleDB Connection and OleDb Command
OleDbConnection con = new OleDbConnection(connectionString);
OleDbCommand cmd = new OleDbCommand();
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection = con;
OleDbDataAdapter dAdapter = new OleDbDataAdapter(cmd);
DataTable dtExcelRecords = new DataTable();
con.Open();
DataTable dtExcelSheetName = con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
string getExcelSheetName = dtExcelSheetName.Rows[0]["Table_Name"].ToString();
cmd.CommandText = "SELECT * FROM [" + getExcelSheetName +"]";
dAdapter.SelectCommand = cmd;
dAdapter.Fill(dtExcelRecords);
con.Close();
GridView1.DataSource = dtExcelRecords;
GridView1.DataBind();
I keep getting error
" The 'Microsoft.ACE.OLEDB.14.0' provider is not registered on the local machine."
Even though I installed Access db and I can see ACE 14.0 still I keep getting this error
Depending on the features of Excel you need you'll need to install Excel on server or the client, or a third party control(s) that understand the format.
If the application is WEB application where the application actually showing the data locally on the client via a web brower : See this MS link : http://support.microsoft.com/kb/162059. Here you're actually sending the xls file/stream to the client.
If you are showing it a WEB application, and shows data on the web page where the rendered content is sent to the client then you need Excel Services on the server (I think this is part of the SharePoint family), or a third party AS.NET control that ready .XLS info and renders it into the page.
If the application is a desktop application that shows excel data in stand alone app where the user logs into the server as a desktop user then you need to have Excel installed on the server. Or you need third party .net control (dependant on app technology WinForms, WFP/Silverlight etc) that can read the .XLS info and present it.
If the application is running on a virtual desktop, say like Citrix, then it's the same as 3.
If all you're doing is reading the files via OLEDB and then working with the data outside of excel then you can install the Access Connectivity Engine for free. This basically the components needed to read various Office data in a need 'service only' package (or driver if you prefer). I don't if allows random access at the cell level, but I know it does allow you to run OLEDB queries over the .XLS file. We use for loading .XLS files into databases.
All of these come with different licensing restrictions and costs. And without any of your use cases, all I can suggest is that you consider that Excel is a chunky set of application components and to use them you need to understand exactly how your application and they will function/interact and also their limitations in any particular deployment scenario you envisage.
Edit:
Further info: If you are running on a 64 server and are using a 32 bit application then the only way I could ACE to work was to install the ACE 2007 and not 2010 version
If you just need to read file content you can use Csv format, wich I think will be the easiest way you can read excel files in your server. you can 'save as' a excel file into *.csv. A csv file is no more than a text file wich is written this way(comma delimited):
"column1","column2","column3"
So now all you just have to do is read a text file.
CVS Files
Hope it helps
You can use OpenXml or ClosedXml - they work on the server
I am creating a application and I want to use a local database stored on the clients local machines. I am debating over if I should use SQLITE or is there something in Visual Studio to help me. The other thing is that I want to create the database programmatically in the users directory when the application is launched.
I am see a few things online but the articles were all about SQL Server stuff and that is not want I want to do with this application. All data will need to be stored on the local machine.
You can use SQL Server Compact, which has tooling in Visual Studio. It's syntax-compatible with SQL Server, but stores its data in a local file, which you can create on the fly (at app startup, for example).
You can create the SQLite database on the fly with the libraries provided from their website. I have used it in many projects for my personal code, as well as it being used in some of the internal architecture of Data Explorer (IBM Product). Some sample C# to create a database file:
if (!Directory.Exists(Application.StartupPath + "\\data"))
{
Directory.CreateDirectory(Application.StartupPath + "\\data");
}
SQLiteConnection conGlobal;
if (!File.Exists(dbGlobal))
{
conGlobal = new SQLiteConnection("Data Source=" + dbGlobal + ";New=True;Compress=True;PRAGMA synchronous = 1;PRAGMA journal_mode=WAL");
conGlobal.SetExtendedResultCodes(true);
firstRun = true;
}
else
{
conGlobal = new SQLiteConnection("Data Source=" + dbGlobal + ";Compress=True;PRAGMA synchronous = 1;PRAGMA journal_mode=WAL");
conGlobal.SetExtendedResultCodes(true);
}
try
{
conGlobal.Open();
}
catch (Exception)
{
//do stuff
}
Simply initiating a connection to the file will create it if the new=true is passed as the connection string. Then you can query it and get results just like you would any database.
You also have the ability to password protect the database files to prevent access to them from just opening them with an SQLite-Shell or a different SQLite DB viewer.
For more info on the pragma statements that are being passed in the connection string, see the following: http://www.sqlite.org/pragma.html
I'm not sure about programmatically (that's probably what you meant, right?) creating the database, but SQL Server Compact Edition has served me well in the past for simple apps. It's embedded and even runs in medium trust.
Context
My appliction uses an SQL database from which it reads my datatables at start of my application. If the application would fail to connect to the SQL DB, I have a local Ms Access .MDB file. I have a separate thread that checks if the local database is outdated.
I have a DataTable which I obtain from my SQL connection --> Verified and working
I can connect to my Access database locally and read from it --> Verified and working
Issue/Question
I'm trying to update my local database by updating it with the DataTable I obtained from my SQL Connection.
public static void UpdateLocalDatabase(string strTableName, OleDbConnection MyConnection, DataTable MyTable)
{
try
{
if (CreateDatabaseConnection() != null)
{
string strQuery = "SELECT * FROM " + strTableName;
OleDbDataAdapter MyAdapter = new OleDbDataAdapter();
OleDbCommandBuilder MyCommandBuilder = new OleDbCommandBuilder(MyAdapter);
MyAdapter.SelectCommand = new OleDbCommand(strQuery, odcConnection);
MyAdapter.UpdateCommand = MyCommandBuilder.GetUpdateCommand();
MyConn.Open();
MyAdapter.Update(MyTable);
MyConn.Close();
}
}
catch { }
}
If I debug this snippet, all variables are what they should be:
strTableName = the correct name for my table
MyConn = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=MyLocation;Persist Security Info=True;JET OLEDB:Database Password=MyPassword;"
MyTable = is the correct table that is also used further on by my application
This process runs through without an error and without using the catch but it does not touch my database, it just doesn't do a thing.
Am I dropping the ball here or just missing the obvious, I have no idea but I browsed many articles and apart for showing the MyAdapter.Update(), there doesn't seem to be much more to it.
Any help is welcome.
Thanks,
Kevin
Does your backup database have to be in access? because if you used SQL Compact Edition it'd be much easier to copy between the two?
Yes, it would either mean attaching it with your installer or just ensuring that all client machines have it pre-installed, it is free however.
if this is an issue then all you need to do (I think, not done it myself)
would be to go to your installer projects properties, click prerequisites and then tick SQL compact so that it will be installed before your application can be used, iv done this before with other frameworks and it just pops up a box with the install shield asking whether they want to download the necessary software and its just one click then it should be done for them.
Do you need a hand on using the compact database also?
One negative by the way is it does lack some higher end features but shouldn't affect average database work
EDIT
if you will be using sql CE you can easily make the databse in VS by clicking data and new data source then following the steps making sure to put sql CE when asked
if it works, you'll end up with an .sdf database
I provided a code snippet that fixed the issue on my related question here: Export SQL DataBase to WinForm DataSet and then to MDB Database using DataSet
I have written an ASP.NET web page with C# behind that runs an existing vb script.
The idea is that the user uploads an Excel spreadsheet (.xls) using the web page, the C# does a few basic checks on the file (file type, file name etc) then saves the .xls to a network location.
The C# then passes the network path of the .xls to the vb script, which gets the required information from the .xls to create a .csv file.
Finally the .csv is passed into a stored procedure and uploaded to a database table.
The problem is that all this runs perfectly when I run the webpage locally on my machine. However when I upload the page to the webserver it does not seem to execute the vb script; instead it just sits there waiting for the script to exit.
Some quick info:
Excel is installed on the web server
The website is set to execute scripts and executables
The script is currently set to 'run as' my personal domain login (this has to change) which has admin on the web server
If I run the script on the webserver using the cmd prompt it works
I'd really appreciate any ideas on what might be going wrong... seriously, I'm pulling my hair out over this one and will consider any idea, no matter how crazy... but, and it's a big one, despite the fact that that there are many other ways of achieving the same result, I'm afraid that for a number of reasons this is what I have to work with :)
Edit
Here is how I call the script
try
{
System.Security.SecureString password = new System.Security.SecureString();
string uspw = "mypassword";
foreach (char c in uspw)
{
password.AppendChar(c);
}
Process scriptProc = new Process();
scriptProc.StartInfo.FileName = #"cscript";
scriptProc.StartInfo.Arguments = scriptPath + " //Nologo " + uploadPath + xlsFileName;
scriptProc.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
scriptProc.StartInfo.UserName = "myusername";
scriptProc.StartInfo.Password = password;
scriptProc.StartInfo.UseShellExecute = false;
scriptProc.Start();
scriptProc.WaitForExit();
scriptProc.Close();
}
catch...
All of the file paths are relative.
The code seems to fail when the script is called. You can clearly see the page waiting for the script to finish. However if you watch the task manager on the web server neither cscript or excel start to run.
I've also stuck a message box right at the start of the script which does not get displayed
Edit 2
It turns out that cscript is running, I just needed to tick the 'All Users' check box in the task manager... I'm still none the wiser though!
Thanks so much in advance
Sounds like you are using automation to control the Excel application itself?
Some quick info:
Excel is installed on the web server
That is generally a bad idea, because the Excel application is not an application that is intended to be automated by a server. Thing might hang because the application is waiting for user input in a dialog somewhere. And it's not scalable for handling operations from multiple users simultaneously.
If the final goal is to extract the data from the excel file and put it in an sql server, I would rather suggest that you use the Jet OLEDB provider to retrieve the data from the excel file, either from your web application, and letting that feed the data into sql server, or let the sql server do it directly. If there is a lot of data in the excel file, the latter might be the best choice
Without seeing the code this is a blind guess - I suggest you check how you are specifying the path to the vb script - make sure you are not using an absolute path, and that the file is in the same location relative to the C# page on the server as it is on your machine.
I have an application that uploads an Excel .xls file to the file system, opens the file with an oledbconnection object using the .open() method on the object instance and then stores the data in a database. The upload and writing of the file to the file system works fine but I get an error when trying to open the file on our production server only. The application works fine on two other servers (development and testing servers).
The following code generates an 'Unspecified Error' in the Exception.Message.
Quote:
System.Data.OleDb.OleDbConnection x = new System.Data.OleDb.OleDbConnection(#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + location + ";Extended Properties='Excel 8.0;HDR=Yes;IMEX=1'");
try
{
x.Open();
}
catch (Exception exp)
{
string errorEmailBody = " OpenExcelSpreadSheet() in Utilities.cs. " + exp.Message;
Utilities.SendErrorEmail(errorEmailBody);
}
:End Quote
The server's c:\\temp and c:\Documents and Settings\\aspnet\local settings\temp folder both give \aspnet full control.
I believe that there is some kind of permissions issue but can't seem to find any difference between the permissions on the noted folders and the folder/directory where the Excel file is uploaded. The same location is used to save the file and open it and the methods do work on my workstation and two web servers. Windows 2000 SP4 servers.
While the permissions issue may be more common you can also encounter this error from Windows file system/Access Jet DB Engine connection limits, 64/255 I think. If you bust the 255 Access read/write concurrent connections or the 64(?) connection limit per process you can get this exact same error. At least I've come across that in an application where connections were being continually created and never properly closed. A simple Conn.close(); dropped in and life was good. I imagine Excel could have similar issues.
Try wrapping the location in single quotes
System.Data.OleDb.OleDbConnection x = new System.Data.OleDb.OleDbConnection(#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source='" + location + "';Extended Properties='Excel 8.0;HDR=Yes;IMEX=1'");
If you're using impersonation you'll need to give permission to the impersonation user instead of/in addition to the aspnet user.
Anything in the inner exception? Is this a 64-bit application? The OLEDB providers don't work in 64-bit. You have to have your application target x86. Found this when getting an error trying to open access DB on my 64-bit computer.
I've gotten that error over the permissions thing, but it looks like you have that covered. I also have seen it with one of the flags in the connection string -- you might play with that a bit.
Yup. I did that too. Took out IMEX=1, took out Extended Properties, etc. I managed to break it on the dev and test servers. :) I put those back in one at a time until it was fixed on dev and test again but still no workie on prod.
not sure if this is the problem you are facing,
but, before disposing of the connection, you should do Connection.Close(),because the Connection.Dispose() command is inherited from Component and does not properly dispose of certain connection resources.
not properly disposing of the connection could lead to access issues.