Azure function read SQLite database - c#

From a third party I am receiving a SQLite '.db3' database file. I wish to read the data stored within the database in an Azure function, but have no requirement to modify the database.
In my Azure function I have also uploaded a text file alongside the .db3 file, I can read the contents of this text file just fine, meaning that I have the URI and read privileges on the folder.
When I try to read some data from the database I get the error 'database is locked'.
Code to read the database is below. This works locally.
List<object> obs = new List<object>();
using(var con = new SQLiteConnection($"URI=file:{fullUri};mode=ReadOnly"))
{
con.Open();
using(var cmd = new SQLiteCommand(sql, con))
{
using(SQLiteDataReader rdr = cmd.ExecuteReader())
{
while(rdr.Read())
{
obs.Add(rdr.GetValues());
}
}
}
con.Close();
}
return obs;
How do I read the database?

I've had this problem before, reading a local file ... more than once. These are the steps I took depending on the scenario:
If your Azure Function is deployed using zipdeploy then under the "Configuration" > "Application Settings", change "WEBSITE_RUN_FROM_PACKAGE" from 1 to 0.
If the file you are trying to reference is saved under wwwroot on the Azure Function I would try put it somewhere else e.g. d:\local.

Related

ASP.NET C# file locked on folder by process not allowing new OleDbConnection connections to different files

I am trying to solve an issue that i have been smashing my head against the wall about. What i am trying to accomplish is to read the table names (sheet names) from an excel file that is stored in a folder on the web server. I am going to use these sheet names to determine what sheet i will read values from. The problem that i am having is that users randomly come across the issue where a file gets locked by the asp.net process and then no other users in different sessions and with different files can access their files on the folder. Once the file is locked i am unable to delete the file from the data folder because it is being used by another process.
The only thing that will free up the folder is to do an app pool refresh. I am running my app pool in X64 to accomondate for the XLSX and XLS files. I have had the server team run the procmon tool to see what processes have the folder locked up and got no useful information.
I have my connection to my file location wrapped in using statements to make sure proper disposal is being done. When a file gets locked or doesn't exit the process of the using statement it does not allow for users to create a new connection to another completely unique and different file in the same location. Users are able to write a file to the folder location and delete a file but not able to execute the conn.Open in the below code. Users are not able to navigate to the folder location and delete the file that is locked by the process either. As i said earlier this happens randomly and is hard to recreate. I have looked into whether the folder had indexing or backup jobs running but they do not.
I have tried to put a lock object around the processing so that no other process can access the file while i am pulling values from the file. The tricky part is that after an app pool refresh i cannot get the file lock to occur for a while....its like it runs out of connection objects and or the app pool bogs down to where 2 processes try and access the file simultaneously or something. Our app pool refreshes every 24 hours so it will automatically release the object and we are able to to delete the file and also able to pull data from other excel sheet on the folder. But we can't run an app pool refresh randomly during the day if we see this locked process issue.
public const string ExcelConnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0;HDR=YES;IMEX=1;ApplicationIntent=ReadOnly;ReadOnly=True;\"";
DataTable dt = ExecuteDataTable(connectionString, String.Format("SELECT * FROM [{0}] ", sheetName.Trim()));
string connectionString = DataServices.ExcelConnection;
string fileConnection = string.Format(connectionString, mappedPath.Trim());
Object lockObject = new Object();
lock (lockObject)
{
// Setup the connection to the file
using (System.Data.OleDb.OleDbConnection conn = new System.Data.OleDb.OleDbConnection(fileConnection))
{
if (File.Exists(mappedPath))
{
try
{
conn.Open();
this.sheetNamesFromFile = conn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, null);
if (this.sheetNamesFromFile.Rows.Count > 0)
{
this.sheetName = RetrieveSheetName(this.sheetNamesFromFile, fileName);
ViewState.Add("SheetName", this.sheetName.ToString().Trim());
if (!string.IsNullOrEmpty(this.sheetName))
{
this.massUploadExcelData = DataServices.GetExcelData(conn.ConnectionString, this.sheetName, fileName); // getexcledata has the following code to grab all data from the sheet name - DataTable dt = ExecuteDataTable(connectionString, String.Format("SELECT * FROM [{0}] ", sheetName.Trim()));
if (this.massUploadExcelData.Rows.Count < 1)
{
this.ShowMessageOnSubmit(this.Labels.GetLabel("norecordsintable"), false);
}
}
else
{
this.ShowMessageOnSubmit(this.Labels.GetLabel("uploadnosheet"), false);
}
}
}
catch (System.Data.OleDb.OleDbException dataExp)
{
EventLogging.LogError("An error has occurred when saving a mass upload file, the file the user is using could have corrupt data : Mapped path = " + mappedPath + " File Path and Name = " + fileName, dataExp);
this.error = "An error has occured when trying to load a mass upload file, user might have corrupt data. exception = " + dataExp;
return string.Empty;
}
}
else
{
EventLogging.LogError("The file does not exist that is trying to be accessed in the application, mapped path - " + mappedPath);
}
}
// Delete the file in data folder, since we already have the datatable of the data and sheet name
if (File.Exists(mappedPath))
{
DeleteFile(mappedPath);
}
}
Any thoughts and direction would be appreciatted.

Unable to find table after successfully connecting to database file

I'm currently a console application tool using C# where user is allowed to input the directory of the database file (which is located somewhere on the desktop), and I am required to get the .db file from the specified location and connect it followed by retrieving it's content from the table into a text file. However I'm getting a SQLite error stating that the table is not found. And whenever I run the code, It creates a copy of the .db file but its empty.
But this error doesn't show when I manually 'copy-paste' a copy of the .db file in my debug folder. So I'm wondering is it a must to keep a copy in the debug folder or is there any other way to allow something like a remote connection. (FYI. I'm really new to C# and SQLite).
connectionString = "DataSource=myDataBase.db";
using (SQLiteConnection connection = new SQLiteConnection(connectionString))
{
connection.Open();
using (SQLiteCommand command = new SQLiteCommand("SELECT File,Path FROM Structure", connection))
{
using (SQLiteDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
//Do some stuffs
}
reader.Close();
connection.Close();
}
}
}
Without a file path, the database file will be searched for in the current directory (whatever it happens to be).
When the database file does not exist, SQLite will happily create a new, empty one.
Include the complete directory in the connection string:
connectionString = "DataSource=C:\\some\\where\\myDataBase.db";

Retrieve Image from MySQL Database over Server

I am making a program which requires getting the local directory of an image from a MySQL database table. For the moment, I have made the directory of the image I want to retrieve equal to C:\Users\User\Pictures\PictureName.PNG in the MySQL table. The method I have written up is able to retrieve this data from the database through a Select statement and set the PictureBox image as a new Bitmap with the path retrieved from the Selectstatement.
I couldn't find the information I was looking for online as most of the answers relate to using the BLOB field in MySQL to store images, but my question is if I were to put my database on a server and with the pictures on there too, would my method scale to accommodate for those changes or would I have to add other functionality in order for it to work on a server as well?
Here is my code below:
public void setImage() {
string path = sql.RetrieveImage(SelectQuery.RetrievePicture());
PictureBox1.Image = new Bitmap(path);
}
public string RetrieveImage(Query query) {
string path = "";
// OpenDatabaseConnection() will open up a connection to the database
// through connection and if successful, will return true.
if (this.OpenDatabaseConnection()) {
// query.ToSql() returns a string format of the select statement
// required to retrieve the local image directory
using (MySqlCommand cmd = new MySqlCommand(query.ToSql(), connection)) {
MySqlDataReader dataReader = cmd.ExecuteReader();
dataReader.Read();
path = dataReader[0] + "";
dataReader.Close();
}
this.CloseDatabaseConnection();
}
return path;
}
Storing images in a DB is a bad idea. Storing paths to image files is a much better way to go, IMO.
This SO question has a few links to really good supporting information.
If you must go that route, however, then yes, the BLOB field (or a VarBinary(MAX) in SQLServer) is the way to do it. You can retrieve those images as Byte[] data.

Download and Concatenate multiple files from database

I have uploaded and stored multiple txt files into a SQL Server database. The idea here is that a user can select the files that they want and then have the C# code read the data from each file and create ONE text file with all the data from each selected. Then make the consolidated file available for download
Any help would be much appreciated.
StreamWriter Writer = new StreamWriter("Filename");
string SQL = "select Item from Table where ID in (1, 2, 3)";
SqlCommand Command = new SqlCommand(SQL, Con);
SqlDataReader Reader = Command.ExecuteReader();
while (Reader.Read())
Writer.WriteLine(Reader["Item"].ToString());
Reader.Close();
Writer.Close();
Making the file available for download is another question.

How to create a connection string outside web.config

Just thinking about this, is it possible to create a connection string outside the ASP.NET's web.config?
Possibly you're looking for configSource?
Yes you can store it anywhere it is just text.... The web.config is just a XML document that stores configuration settings about your application. You could just as easily create another XML file or a text file and read it in from there. You just wouldnt be able to use:
ConfigurationManager.ConnectionStrings[].ConnectionString
You can create a connection string through the usage of .udl file.
UDL File Creation :
Right-click on the desktop, or in the folder where you want to create the file.
Select New, then Text Document.
Give the Text Document any name with a .udl extension ("Show file extensions" must be enabled in folder options).
A window will pop up warning that "If you change a filename extension, the file may become unusable. Are you sure you want to change it?" Select Yes.
You have now successfully created a UDL file.
Now you need to implement the settings inside the .udl file according to your requirements. A video tutorial has been provided to explain you the whole procedure of using .udl file to create a connection string for MS SQL Server.
http://visiontechno.net/studymats/udlcreation.html
You can have it in another .config file that gets pulled in by your web.config like this:
<appSettings file="../Support/config/WebEnvironment.config">
</appSettings>
You can then use it in your code like this:
System.Configuration.ConfigurationManager.AppSettings["DefaultConnection"]
We have it such that this file isn't physically under our site, but it is virtually under it. That is the "Support" directory above is a virtual directory. Details can be found HERE.
You can use following in case of MSSQL server
string connectionString = "Your Connection string"
using (SqlConnection con = new SqlConnection(connectionString))
{
//
// Open the SqlConnection.
//
con.Open();
//
// The following code uses an SqlCommand based on the SqlConnection.
//
using (SqlCommand command = new SqlCommand("SELECT TOP 2 * FROM Dogs1", con))
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine("{0} {1} {2}",
reader.GetInt32(0), reader.GetString(1), reader.GetString(2));
}
}
}

Categories