My users want data from my application in Excel. The data resides in a SQL Server database but I don't want the users to have direct access to the database, I would rather provide them a web service to get the data. What is the best way to move data from SQL Server to Excel via a web service?
You can do it as a straight asp.net page and return a .csv file. If you change the mimetype to text/csv, it should default to open in excel. This would be the easiest approach, and one that I've used in the past with great success.
The following code will generate an excel file from a datatable, you can just stream this to the user
public static void CreateExcelFromDataTable(string filename, DataTable dt) {
DataGrid grid = new DataGrid();
grid.HeaderStyle.Font.Bold = true;
grid.DataSource = dt;
grid.DataMember = dt.TableName;
grid.DataBind();
// render the DataGrid control to a file
using (StreamWriter sw = new StreamWriter(filename)) {
using (HtmlTextWriter hw = new HtmlTextWriter(sw)) {
grid.RenderControl(hw);
}
}
}
you can also blow back an html page with a table on it with a .xls filename, excel knows how to open this as well
Have the Web service emit a string buffer where cells are delimited by the tab character and rows by a carriage return/line feed. Then pipe the results of this into Excel with an Excel Web query. It's cheap, quick, a little bit dirty, but good for simple processes.
I'm in favor of Excel Web Query (Data/Import External)
Also, there is a way to post data from Excel back to the web site. At least it's working in MS Sharepoint
Related
We have this poor man's weekly task, which essentially loads a bunch of CSVs, massages them a bit, dumps them into preloaded Excel template and sends them as an attachment to mgmt. Then they play with it using excel filters and charts, etc (not important here).
What is important is that this used to be a .NET Framework app which we have to migrate to .net core, and the initial author did this by constructing an ADODB recordset and using CopyFromRecordset method on a Range to dump the entire table. For example, this constructs the recordset:
internal static ADODB.Recordset ConvertToADODBRecordSet(this List<MyData> data)
{
var result = new ADODB.Recordset { CursorLocation = ADODB.CursorLocationEnum.adUseClient };
var resultFields = result.Fields;
resultFields.Append("Date", ADODB.DataTypeEnum.adDate);
resultFields.Append("Hour", ADODB.DataTypeEnum.adInteger);
resultFields.Append("Code", ADODB.DataTypeEnum.adVarWChar, 16);
result.Open(CursorType: ADODB.CursorTypeEnum.adOpenStatic, LockType: ADODB.LockTypeEnum.adLockOptimistic);
foreach (var dr in data)
{
result.AddNew();
resultFields[0].Value = dr.Date;
resultFields[1].Value = dr.Hour;
resultFields[2].Value = dr.Code;
}
return result;
}
...
var table = sheet.ListObjects["CodesTable"];
table.InsertRowRange.CopyFromRecordset(data.ConvertToADODBRecordSet());
As far as I see, there is not ADODB support in .net framework, I couldn't even try it with supported database objects because, well, there is no database here, recordset is manual and judging by other peoples' attempts it wouldn't work anyway. Entering values in cells one by one is not feasible, there are a dozen sets, each with over 100K rows, it takes forever.
So, how does one go about injecting a manual range of values in Excel using a single call C# interop on .net core?
PS: I cannot use any library which directly just modifies xlsx file. Upon injecting data, a bunch of charts and pivot tables are refreshed by Excel, so whatever alternative solution might come up, it needs to act as a full Excel and update all the sheets before saving.
Ok, I found a solution, in case anyone needs it. I have abandoned the data transfer route and leaned on clipboard to do the job. "Copying" tab delimited data and then pasting it in the table inject region did the trick. You will however have to convert the pure .net console project into *-windows targeted project and add OutputType of WinExe and UseWindowsForms to true (or WPF) so that Clipboard class can be available (its not in pure console project). You do not have to create any forms or Run the winForms/WPF though, just let it run as console app in Main.
using var writer = new StringWriter();
var cfg = new CsvConfiguration(CultureInfo.GetCultureInfo("en-us"))
{
HasHeaderRecord = false,
Delimiter = "\t"
};
using var csv = new CsvWriter(writer, cfg);
csv.WriteRecords(data);
var dataObject = new DataObject();
dataObject.SetText(writer.ToString());
System.Windows.Forms.Clipboard.SetDataObject(dataObject, true);
// paste to excel
var table = sheet.ListObjects["CodesTable"];
table.InsertRowRange.PasteSpecial(XlPasteType.xlPasteAll, XlPasteSpecialOperation.xlPasteSpecialOperationAdd);
So the situation is the following. I have an Angular front end project and I want to import an excel file from the front end together with some additional properties.
The front end I will handle, but I have a couple of questions for the back end:
What should I be receiving as a variable type in the back end for the excel file?
I want to foreach the data from the excel file and get only specific data. For example, I have one sheet only with rows Name, Age and Number of transactions. I want to take only the name and number of transactions and save that information in a new instance of a class I have within my application.
How do I do that?
required before you start the OPEN XML SDK
First in asp you need to defined your method with a IFormFile variable or use the FileUpload Helper class
then you need to move the data into a stream eg IFormFile.CopyToAsync(Stream)
finally open the spreadsheet for read only access so you can read the data
this would look something like this
public async Task<IActionResult> OnPostUploadAsync(List<IFormFile> files)
{
foreach(var file in files)
{
using var mem = new MemoryStream();
await file .CopyToAsync(mem);
var doc = SpreadsheetDocument Open(mem, false);
...
this will open the file and parse the data in it as an excel spreadsheet
you can then use the spreadsheet methods to extract the data you require from inside the document
Im trying to export an excel document created from a data table to the browser/client. This works fine in an aspx code behind file, but when I have moved the method to a .cs file using MVC the method does not generate the excel file in the browser downloads bar, the response is returned as text and encoded characters in the request response, below is the code in the controller that isn't generating the file (the code saves the file to the hard disc firsts, which works correctly just doesn't send to the browser)
protected void ExportToExcel_Click(object sender, EventArgs e)
{
var fromdate = Convert.ToDateTime(DateFrom);
var todate = Convert.ToDateTime(DateTo);
var type = ddlTransactionType.SelectedValue;
var transstatus = P2UFramework.Payment.BrainTree.GetTransactionStatus(type);
var transdetails = P2UFramework.Payment.BrainTree.Transactions_ByDate(transstatus, fromdate, todate.AddDays(1));
//var dt = P2UFramework.Utility.Conversion.ListToDataTable.ToDataTable(transdetails);
var dt = new DataTable();
dt.Columns.Add("Date");
dt.Columns.Add("TransactionId");
dt.Columns.Add("PatientId");
dt.Columns.Add("PatientDetails");
dt.Columns.Add("Email");
dt.Columns.Add("RxOrderNo");
dt.Columns.Add("PODOrderNo");
dt.Columns.Add("OTCOrderNo");
dt.Columns.Add("BrainTreeTransactionId");
dt.Columns.Add("Amount");
dt.Columns.Add("TransactionStatus");
foreach (var item in transdetails)
{
dt.Rows.Add(item.TransactionDate, item.P2UTransactionId, item.CustomerId, item.CustomerName, item.Email, item.PrescriptionOrderID,
item.PodOrderID, item.OtcOrderID, item.BrainTreeTransactionId, item.Amount, item.Status);
}
// Export to excel
string outputFile = KwibooCommon.DataExtract.Write(dt, Server.MapPath("~/_Assets/"), KwibooCommon.DataExtract.Format.Excel);
try
{
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + outputFile.Split('\\').Last());
HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
HttpContext.Current.Response.WriteFile(outputFile);
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.Close();
}
catch (ThreadAbortException ex)
{
throw ex;
}
finally
{
try
{
File.Delete(outputFile);
}
catch (Exception) { }
}
}
Rob,
You're going to want to put some layers between the endpoint and ultimately reading the excel file for multiple reasons.
First, excel files by nature are extremely volatile, and not meant to be concrete data sources like SQL or even Access.
Second, you're combining a series of concerns into a single method that belong in multiple classes. Take it from experience that this is going to be a nightmare for you to maintain in the future. Especially if you're a VBA guru, that excel file is macro enabled, and you're going to have to maintain it moving forward.
Let's assume you have to live off of the excel file. Read it into access at the very least. SQL server express is free and can handle .csv imports easily out of the box. The server connection wizard in VS can handle .mdb files if need be. Import the data, have a plan and an automated solution to maintain it. Ideally, have a service that reads the csv from the excel file on a regular basis into SQL.
I've been in the situation of having to develop solutions with nothing but office. It's not fun, but there are ways to make it better.
Have a controller class that provides an endpoint and nothing else. Have a service layer that handles business logic, and have a repository layer that does nothing but read from your data source. I'd recommend it not be an .mdb file but if it is, VS can handle it.
I hope I've given you a brief overview of how to handle the situation. Please ask if you have any specific questions. I've been there, I'm happy to help.
So I have some code that creates an excel worksheet from Smartsheets and then extracts that information from the excel worksheet into SQL. Thing is the code works if I run each part seperately but if I run it at the same time it will create the table, but it won't input the data. Below I will show each part in the main program. I don't think it is necessary to show the rest of the code because as I say it works seperately.
//Make an Excel sheet from smartsheet
Smartsheet smartsheet = new Smartsheet();
long excelSmartsheetID = smartsheet.getSmartSheetID(currentWorkSheet);
smartsheet.createExcel(excelSmartsheetID);
//Extract Data From Excel into SQL
SSIS excelToSQL = new SSIS();
excelToSQL.storeSmartSheetDataToSQL();
So I am not sure what is going on here. I have put the thread to sleep for 10 seconds in between the two sections but it still doesn't work. Completely lost as to what might be the problem. I should add I am using SSIS to connect to the excel sheet and create it in SQL. Please let me know if you require more information.
It sounds like the Excel file is still open when trying to access it a second time. When an Excel file is open for writing it becomes locked which can prevent another process (in your case SSIS) from editing the file. This can be confirmed using the Smartsheet C# SDK with code like the following which never closes the file after writing to it.
// Set the Access Token
Token token = new Token();
token.AccessToken = "YOUR_TOKEN";
// Use the Smartsheet Builder to create a Smartsheet
SmartsheetClient smartsheet = new SmartsheetBuilder().SetAccessToken(token.AccessToken).Build();
BinaryWriter output = new BinaryWriter(new FileStream("c:\\file.xls", FileMode.Create));
smartsheet.Sheets().GetSheetAsExcel(8325033727682436L, output);
Console.WriteLine("Done writting");
System.Threading.Thread.Sleep(100000);
Run the above code and after it opens and writes to the file it will sleep for a very long time. While the code is sleeping you can try to manually open the Excel file and you will get a dialog like the following showing that we still have the Excel file open (from our code) even though we finished writing to it.
The solution to this issue is to close the Excel file as soon as we are done writing to it. This can be accomplished by using the close() method on the stream or with the using statement. I prefer the using statement so an example of that is below:
// Set the Access Token
Token token = new Token();
token.AccessToken = "YOUR_TOKEN";
// Use the Smartsheet Builder to create a Smartsheet
SmartsheetClient smartsheet = new SmartsheetBuilder().SetAccessToken(token.AccessToken).Build();
using (BinaryWriter output = new BinaryWriter(new FileStream("c:\\file.xls", FileMode.Create)))
{
smartsheet.Sheets().GetSheetAsExcel(8325033727682436L, output);
}
Console.WriteLine("Done writting");
System.Threading.Thread.Sleep(100000);
Now if we run the above code it will sleep at the end but this time the Excel file will not be locked since the using statement closed the file as soon as we finished writing to it.
I have a table in my database called Employeee.
I need to write the database data to a file.
How do I do it in asp.net mvc C#?
i have tried Datatable approach,but it failed.
Do It the same way you would do in a winform, wpf or so.
For example, if your text document has to be in JSON, use :
using(TextWriter writer = new TextWriter(#"yourfilename.json")){
writer.Write(JsonConvert.SerializeObject(db.Employeee));
}
In my example, don't forget to import the Newtownsoft.Json package.
You can also formate everything in XML, CSV...