ASP.NET MVC - Save Excel Contents to Database - asp.net

I would like to add a functionality to my web application where user can upload an excel file that would probably look like this (i will be supplying an excel file template that the user can fill up):
Name Address Phone
John California 000-111
Matt Seattle 000-222
...
And pass each line after the headings Name-Address-Phone to my registration controller or service. Now my question is what would be the best way (for user experience; speed is important) to do this?
I am not looking for a full working code, I'm just looking for the most efficient approach with regards to speed.

You should create a stored procedure which holds the insert logic.Once the user uploads the Excel file you can open it using Excel interop, get the captured data and call the insert stored procedure.If you need even faster insert speeds you can always use SQL Bulk Copy.
1.In your MVC project add a reference to Microsoft.Office.Interop.Excel.dll
2.Create a View which prompts the user to upload an Excel file.
#using (Html.BeginForm("Import", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.Raw(ViewBag.Error)
<span>Excel File </span><input type="file" name="excelfile" />
<br />
<input type="submit" value="Import" />
}
3.Create a controller action which opens the Excel file -> loops through the rows -> inserts the data into SQL
[HttpPost]
public ActionResult Import(HttpPostedFileBase excelFile)
{
//Add this to the using statements after adding a refrence to Microsoft.Office.Interop.Excel.dll - using Excel = Microsoft.Office.Interop.Excel;
if ((excelFile.ContentLength != 0) && (excelFile.FileName.EndsWith("xls") || excelFile.FileName.EndsWith("xlsx")))
{
string path = Server.MapPath("~/Files/" + excelFile.FileName);
if (!System.IO.File.Exists(path))
{
excelFile.SaveAs(path);
Excel.Application application = new Excel.Application();
Excel.Workbook workbook = application.Workbooks.Open(path);
Excel.Worksheet worksheet = (Excel.Worksheet)workbook.ActiveSheet;
Excel.Range range = worksheet.UsedRange;
for (int i = 2; i < range.Rows.Count + 1; i++)
{
string name = ((Excel.Range)range.Cells[i,1]).Text;
string address = ((Excel.Range)range.Cells[i,2]).Text;
string phone = ((Excel.Range)range.Cells[i,3]).Text;
//Write the logic to add the values to the database
}
}
}
return View();
}
You could also make the action asynchronous but it doesn't really help because writing to a database is an IO operation so async won't do anything.

You can make use of OleDb to connect to your excel file. After successfull connection you can populate a DataTable with the rows in your excel file and then do a foreach to pass each row to your controller.
void Process(string path)
{
try
{
string connString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + path + ";Extended Properties=\"Excel 8.0;HDR=Yes;IMEX=1\";";
using (var connection = new OleDbConnection(connString))
{
using (var command = new OleDbCommand("select * from [SheetName$]", connection))
{
connection.Open();
using (var adapter = new OleDbDataAdapter(command))
{
DataTable dataTable = new DataTable();
adapter.Fill(dataTable);
foreach (DataRow row in dataTable.Rows)
{
string Name, Address, Phone = string.Empty;
try
{
Name = row["Name"].ToString();
Address = row["Address"].ToString();
Phone = row["Phone"].ToString();
//new RegistrationController(Name, Address, Phone);
}
catch (Exception ex)
{
// Handle exceptions
}
}
}
}
}
}
// Might be possibly thrown when opening connection
catch (OleDbException ex)
{
// Handle exceptions
}
// Might be possibly thrown when filling datatable
catch (InvalidOperationException ex)
{
// Handle exceptions
}
}

Related

Xamarin forms how to Get existing local database

How do you Get an existing database from a device or emulator ?
device not rooted
I'm using Microsoft.WindowsAzure.MobileServices
public bool InitialiseDb()
{
try
{
Store = new MobileServiceSQLiteStore(offlineDbPath);
Store.DefineTable<Products>();
_client.SyncContext.InitializeAsync(Store);
this.productTable = _client.GetSyncTable<Products>();
return true;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
return false;
}
}
You can copy the existing database into a folder you can access
Create path to database :
string filepath = "data/data/[package-name]/files/[name-of-db]";
You can get your package name from your android project options
then use the following code to extract it:
string filepath = "data/data/com.foo.foo/files/localstorage.db";
var bytes = System.IO.File.ReadAllBytes(filepath);
var fileCopyName = string.Format("/sdcard/Database_{0:dd-MM-yyyy_HH-mm-ss-tt}.db", System.DateTime.Now);
System.IO.File.WriteAllBytes(fileCopyName, bytes);

The most straightforward way to download a file in mvc

I am currently saving an excel file like so on my c drive.
public ActionResult Export()
{
try
{
Excel.Application application = new Excel.Application();
Excel.Workbook workbook = application.Workbooks.Add(System.Reflection.Missing.Value);
Excel.Worksheet worksheet = workbook.ActiveSheet;
var people = db.People.ToList();
worksheet.Cells[1, 1] = "Last Name";
worksheet.Cells[1, 2] = "First Name";
int row = 2;
foreach (var person in people)
{
worksheet.Cells[row, 1] = person.PersonFName;
worksheet.Cells[row, 2] = person.PersonLName;
row++;
}
workbook.SaveAs("c:\\test\\worksheet.xls");
workbook.Close();
Marshal.ReleaseComObject(workbook);
application.Quit();
Marshal.FinalReleaseComObject(application);
ViewBag.Result = "Done";
}
catch(Exception ex)
{
ViewBag.Result = ex.Message;
}
return File("c:\\test\\workseet.xls", "application/vnd.ms-excel", "workseet.xls");
// return View("Success");
}
I can go to c:\\test\workseet.xls and it exists there I can do what ever with it...
I am wanting to transform my method from return a view to return a file download...
I figured that it was as simple as this:
return File("c:\\test\\workseet.xls", "application/vnd.ms-excel", "workseet.xls");
However when I do this method and click the link to download, it gives me this error.
The process cannot access the file 'c:\test\workseet.xls' because it is being used by another process.
This duplicate question is just one of those that show how to use EPPlus to generate Excel files on the server side in a scaleable manner. It's actually a lot easier than using Excel interop and a lot faster. You don't even have to save the file to the disk.
public ActionResult ExportData()
{
//Somehow, load data to a DataTable
using (ExcelPackage package = new ExcelPackage())
{
var ws = package.Workbook.Worksheets.Add("My Sheet");
//true generates headers
ws.Cells["A1"].LoadFromDataTable(dataTable, true);
//Save the workbook to a stream
var stream = new MemoryStream();
package.SaveAs(stream);
string fileName = "myfilename.xlsx";
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
stream.Position = 0;
return File(stream, contentType, fileName);
}
}
You can use LoadFromDataTable to fill a sheet from a data table or LoadFromCollection to load data from a collection, eg List<Sale>.
Both methods return an ExcelRange object (a range of cells) that you can use to format individual cells, rows, and columns. You can also create tables from a range and apply themes.
The duplicate goes even farther and shows how you can avoid even the MemoryStream

How do I check whether a Local Publication exists given the publication name and how do I delete it along with everything associated with it?

I'm working in ASP .NET and I need to do a couple of things:
Check whether the Publication I'm about to create already exists.
If it does, delete it along with EVERYTHING related to it (jobs, etc. including anything at the subscriber side).
I started with this:
public static bool PublicationExists(string server)
{
string finalConnString = Properties.Settings.Default.rawConnectionString.Replace("<<DATA_SOURCE>>", server).Replace("<<INITIAL_CATALOG>>", "tempdb");
using (var conn = new SqlConnection(finalConnString))
{
using (var cmd = new SqlCommand("what is the query to check whether a publication exists?", conn))
{
conn.Open();
cmd.ExecuteNonQuery();
using (var da = new SqlDataAdapter(cmd))
{
using (var ds = new DataSet())
{
da.Fill(ds);
if (ds.Tables[0].Rows.Count > 0)
{
return true;
}
return false;
}
}
}
}
}
Now...
If (PublicationExists(server) == true)
{
//I want to delete the publication along with everything associated with it.
}
How would I go about doing this?

How to cancel and delete the uploading file in asp.net mvc 3?

I am using a filestream to receive a large file in my controller. codes below:
[HttpPost]
public JsonResult Create(string qqfile, Attachment attachment)
{
Stream inputStream = HttpContext.Request.InputStream;
string fullName = ingestPath + Path.GetFileName(qqfile);
using (var fs = new FileStream(fullName, FileMode.Append, FileAccess.Write))
{
try
{
var buffer = new byte[1024];
int l = inputStream.Read(buffer, 0, 1024);
while (l > 0)
{
fs.Write(buffer, 0, l);
l = inputStream.Read(buffer, 0, 1024);
}
return Json(new {success = "true"});
}
catch (Exception)
{
return Json(new {success = "false"});
}
finally
{
inputStream.Flush();
inputStream.Close();
fs.Flush();
fs.Close();
}
}
}
And in my page ajax method, I add a button to cancel the file uploading and delete the unfinished file from disk. The ajax request to the action named "Cancel":
[HttpPost]
public JsonResult Cancel(string filename)
{
string localName = HttpUtility.UrlDecode(filename);
string fullName = ingestPath + Path.GetFileName(localName);
if (System.IO.File.Exists(fullName))
{
System.IO.File.Delete(fullName);
}
return Json(new {cancle = true});
}
The problem is: the file can not delete, and the exception message is
the process cannot access the file 'e:\tempdata\filename_xxx.xxx'because it is being used by another process.
I think it is because that ,the filestream of this file is not closed. How can I close this filestream and delete the file in my 'Cancel' action?
--
OH! I found a method to resolve it now.
using (var fs = new FileStream(fullName, FileMode.Append, FileAccess.Write))
It is to simple, just declaration a fileshare property: FileShare.Delete
using (var fs = new FileStream(fullName, FileMode.Append, FileAccess.Write, FileShare.Delete))
I spent 4 hours to google and debug and test and try to resolve it. Just 10 mins after I asked stackoverflow, I got the answer by myself. Interesting! And hope it is useful to someone too.
You could put that file stream in a session then use that session in your cancel action to close the stream.

How to convert array of byte to original file (to provide download of file)

I m using Opendialogbox to read the file. Then stored the file in byte[] array.
file --> byte []
byte[] --> stored on SQL AZure in varbinary(max) field.
Here is my code:
OpenFileDialog ofd = new OpenFileDialog();
if ((bool)ofd.ShowDialog())
{
FileStream fileStream = ofd.File.OpenRead());
byte[] buffer = new byte[fileStream.Length];
int read = 0;
using (BinaryReader binaryReader = new BinaryReader(fileStream))
{
do
{
read = binaryReader.Read(buffer, 0, Convert.ToInt32(fileStream.Length));
// Stored the File in byte[] Array buffer
} while (read > 0);
}
}
Now I want to convert this byte array to the original file (like .doc,.txt,jpeg). i know the extension in which file is to be convert.
SQL AZure ---> byte[] // done
byte[] ---> to original file. // Problem
Please give solution to download the file.
One way - not necessarily the best - is as follows:
using (MemoryStream ms = new MemoryStream(theBytes))
{
using (FileStream fs = new FileStream(string.Format("C:\\tempfile.{0}", theExtension)))
{
ms.WriteTo(fs);
}
}
namespace FileSaveDialogDemo
{
public partial class MainPage : UserControl
{
#region Fields
SaveFileDialog dialog= new SaveFileDialog();
#endregion
#region Constructors
public MainPage()
{
InitializeComponent();
this.dialog = new SaveFileDialog();
try
{
this.dialog.DefaultExt = ".txt";
this.dialog.Filter = "Text Files|*.txt|Log Files|*.log|All Files|*.*";
this.dialog.FilterIndex = 2;
}
catch ( Exception ex )
{
this.tblError.Text = "Error configuring SaveFileDialog: " + ex.Message;
}
}
#endregion
private void btnSaveFile_Click( object sender, RoutedEventArgs e )
{
bool? dialogResult = this.dialog.ShowDialog();
if ( dialogResult == true )
{
try
{
byte[] fileBytes; // your varbinary file from database
using (Stream fs = (Stream)dialog.OpenFile())
{
fs.Write(fileBytes, 0, fileBytes.Length);
fs.Close();
lblMsg.Content = "File successfully saved!";
}
}
catch ( Exception ex )
{
this.tblError.Text = "Error calling service: " + ex.Message;
}
}
} // End of Function
}// End of MainPage class
}
It seems the issue you have has probably nothing to do with saving a binary file; it is more likely a basic security issue. Try saving to a path on which you have programmatic write access. For example, try saving to your My Documents directory instead of C:. Try using the Environment.SpecialFolder enumeration like this, and append the file name + extension.
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
You have a number of other ways to work around this issue, including starting Visual Studio in Elevated Mode (run as Administrator), and/or allow "Everyone" write access to your C:\ drive. But I wouldn't recommend these techniques necessarily; consider saving to a folder where the security settings are lower than c:\, such as My Documents.

Resources