Interop Exception when looking at cell data to perform formatting - c#

I have a small application that queries a DB on a networked Windows Server running SQL Server and outputs the data to an Excel file. I am working on formatting the excel file how I need and I'm running into an exception I've never seen when trying to view the data in the cells. Here is my code:
xlWorkSheet.Activate();
xlWorkSheet.Application.ActiveWindow.ScrollRow = 1;
xlWorkSheet.Application.ActiveWindow.SplitRow = 1;
xlWorkSheet.Application.ActiveWindow.FreezePanes = true;
xlWorkSheet.Cells[1, 1].EntireRow.Font.Bold = true;
xlWorkSheet.Columns.AutoFit();
for (i = 0; i <= xlWorkSheet.Rows.Count; i++)
{
if(xlWorkSheet.Cells[i,5].Value2 == "PAST DUE")
{
xlWorkSheet.Cells[i, 5].Interior.Color = Excel.XlRgbColor.rgbRed;
}
}
This is the exception I'm receiving:
System.Runtime.InteropServices.COMException: 'Exception from HRESULT: 0x800A03EC'
All other applications I've written that look at cell data have never had any problem with this same type of usage.
The Exception happens at this line:
if(xlWorkSheet.Cells[i,5].Value2 == "PAST DUE")

Related

Method in Service that uses excel isn't saving and doesn't appear to produce an exception

I have a problem with some code in a service I have. The method just creates a datatable of the report that needs to be created and then writes it to an existing excel file. The problem is that it fails at the save of the file. Somewhat more oddly, it doesn't appear to be catching errors, and I don't know why. I've included the code below. Of note:
excel.Visible=true; doesn't seem to make the excel sheet visible each time so I can't really watch what's going on in the excel itself. I assume it's not becoming visible because it's a service, but I don't really know.
I know that the datatable is producing output as I've had the log (Which is just a text file where I can write events and errors) writes both the cells value and it's location and it has never stopped in the Foreach loop or the for loop within it
I know that it's failing at the wb.Save(); because the Log.WriteLine("WriteTIByEmp 4"); successfully writes to the text file, but the Log.WriteLine("WriteTIByEmp 5"); does not.
The catch (Exception ex) also doesn't seem to be working, as it doesn't write anything about the exception but doesn't even write the Log.WriteLine("Catching Exception");, so I'm a bit lost.
Edit: Just to note, this is all using Interops in the excel portion. It's just that the "using Microsoft.Office.Interop.Excel" is declared at the top of the class to save time and typing as almost all the methods in this particular class are using excel. The excel file is always opening in this process, I can see it in the task manager, and I have had other methods successfully write to excel files in this process. Only this particular method has had issues.
public void WriteTIByEmp(CI.WriteReport Log)
{
try
{
System.Data.DataTable Emps = Pinpoint.TICardsByEmpStatsDaily.GetTICardsByEmployer();
Log.WriteLine("WriteTIByEmp 1");
Application excel = new Application();
excel.Visible = true;
Workbook wb = excel.Workbooks.Open(TIEMPPath);
Worksheet ws = wb.Worksheets[1];
ws.Range["A:G"].Clear();
Log.WriteLine("WriteTIByEmp 2");
int RowNum = 0;
int ColCount = Emps.Columns.Count;
Log.WriteLine("WriteTIByEmp 3");
foreach (DataRow dr in Emps.Rows)
{
RowNum++;
for (int i = 0; i < ColCount; i++)
{
ws.Cells[RowNum, i + 1] = dr[i].ToString();
Log.WriteLine("Cell Val:" + dr[i].ToString() + ". Cell Location: " + RowNum + "," + i);
}
}
Log.WriteLine("WriteTIByEmp 4");
wb.Save();
Log.WriteLine("WriteTIByEmp 5");
wb.Close();
Log.WriteLine("WriteTIByEmp 6");
excel = null;
Log.WriteLine("WriteTIByEmp 7");
}
catch (Exception ex)
{
Log.WriteLine("Catching Exception");
var st = new StackTrace(ex, true);
var frame = st.GetFrame(0);
var line = frame.GetFileLineNumber();
string msg = "Component Causing Error:" + ex.Source + System.Environment.NewLine + "Error Message: " + ex.Message + System.Environment.NewLine + "Line Number: " + line + System.Environment.NewLine + System.Environment.NewLine;
Log.WriteLine(msg, true);
}
}
Meaby try to use Interops
i don't understand how Your code can start Excel application
by this line :
Application excel = new Application();
try this
Microsoft.Office.Interop.Excel.Application xlexcel;
xlexcel = new Microsoft.Office.Interop.Excel.Application();
xlexcel.Visible = true;
I have been in similar situation.
Note: While using Interop Excel is a dependency as well as other processes accessing the file could cause issues. Therefore, I recommend using EPPlus Nuget Package as it works wonders.
https://www.nuget.org/packages/EPPlus/
Please refer to the below sample code.
FileInfo fi = new FileInfo(ExcelFilesPath + "myExcelFile.xlsx");
using (ExcelPackage pck = new ExcelPackage())
{
// Using Existing WorkSheet 1.
ExcelWorksheet ws = pck.Workbook.Worksheets[1];
// Loading Data From DataTable Called dt.
ws.Cells["A1"].LoadFromDataTable(dt, true);
// If you want to enable auto filter
ws.Cells[ws.Dimension.Address].AutoFilter = true;
// Some Formatting
Color colFromHex = System.Drawing.ColorTranslator.FromHtml("#00B388");
ws.Cells[ws.Dimension.Address].Style.Fill.PatternType = ExcelFillStyle.Solid;
ws.Cells[ws.Dimension.Address].Style.Fill.BackgroundColor.SetColor(colFromHex);
ws.Cells[ws.Dimension.Address].Style.Font.Color.SetColor(Color.White);
ws.Cells[ws.Dimension.Address].Style.Font.Bold = true;
ws.Cells["D:K"].Style.Numberformat.Format = "0";
ws.Cells["M:N"].Style.Numberformat.Format = "mm-dd-yyyy hh:mm:ss";
ws.Cells[ws.Dimension.Address].AutoFitColumns();
pck.SaveAs(fi);
}
You can refer to the above code from my project. I am loading the DataTable data into my excel file by providing the Range or Starting Cell.
I had found the issue. The Excel file was open on someone else's computer which resulted in it not being able to save the file, but it couldn't display the excel popup because excel wouldn't become visible (I still don't know why but Probably something to do with it being a service). So it just couldn't save but it wasn't a code error so it didn't show up in the log and couldn't continue so the code was just stuck. I'll make a copy for the purposes of updating in the future.

c# Rotativa issue in production server using user built template pdf generation

i am developing a enterprise app in c# .net. There are many pdf documents generated in the system. I use Rotativa for pdf handling. There is one pdf which uses user created template in the system. System fetches data from the system and replaces the template variables with the dynamic values from server and downloads the pdf. This particular pdf is working fine in my local and development server, but fails in the production server. Will be glad if somebody could help. i have attached the error and the code. please have a look.
public ActionResult GenerateRedemptionLetterGift(int id, int templateId)
{
try
{
int RedTempId = templateId; //Convert.ToInt32(Request.QueryString["templateId"]);
int type = 2;
RedemptionCode RedemptionObj = new RedemptionCode();
RedemptionObj = BlObj.GetRedemptionDetail(id);
return new Rotativa.MVC.ActionAsPdf("ReturnTemplate", new { id, RedTempId, type }) { FileName = "Redemption_Letter_" + RedemptionObj.Id.ToString() + ".pdf" };
}
catch (Exception ex)
{
throw new Exception("Main Method", ex);
}
}
here i call a function ReturnTemplate as ActionAsPdf where all the data is fetched and replaced in the user created template.
public ActionResult ReturnTemplate(int id, int RedTempId, int type)
{
try
{
RedemptionTemplateBO RedTemp = new RedemptionTemplateBO();
RedTemp = BlObj.GetRedemptionTemplateForEdit(RedTempId);
Hashtable TempStrings = new Hashtable();
if (type == 1)
{
TempStrings = GenerateRedemptionHashTable(id);
}
else if (type == 2)
{
TempStrings = GenerateRedemptionHashTableGift(id);
}
StringBuilder builder = new StringBuilder();
builder.Append("<html><head><title>Redemption Letter</title></head><body><style> #font-face {font-family: myFirstFont;src: url(~/fonts/Roboto-Regular.ttf);} p{font-family: 'Roboto', sans-serif;color: #3e3e3e;font-size: 15px;font-weight: 400;margin-bottom: 10px}</style>");
builder.Append(RedTemp.TemplateContent);
builder.Append("</body></html>");
foreach (string key in TempStrings.Keys)
{
builder.Replace("[" + key + "]", (string)TempStrings[key]);
}
return Content(builder.ToString());
}
catch( Exception ex)
{
throw new Exception("Return Template", ex);
}
}
I have checked in the local using a break point, if i am getting the correct data in the string for returning in the second method. Its coming fine.
Its running fine in both local and development server. I am getting the expected pdf.
But when i run it in production. i am running into an error, and it doesnt seem to be hitting the try catch block also.
Server Error in '/' Application.
Error: Failed loading page http://app.com/Redemption/ReturnTemplate/185?RedTempId=3&type=2 (sometimes it will work just to ignore this error with --load-error-handling ignore)
Exit with code 1 due to network error: RemoteHostClosedError
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Exception: Error: Failed loading page http://app.com/Redemption/ReturnTemplate/185?RedTempId=3&type=2 (sometimes it will work just to ignore this error with --load-error-handling ignore)
Exit with code 1 due to network error: RemoteHostClosedError
This is the last few stack trace
Rotativa.Core.WkhtmltopdfDriver.Convert(DriverOptions options, String html) +793
Rotativa.MVC.AsPdfResultBase.CallTheDriver(ControllerContext context) +27
Rotativa.MVC.AsPdfResultBase.BuildPdf(ControllerContext context) +203
Rotativa.MVC.AsPdfResultBase.ExecuteResult(ControllerContext context) +27
WkhtmltopdfDriver takes too long to respond from production server.
Could it be due to some outgoing calls in Rotativa server. But still my other pdf generations work fine with rotativa in the production server.
We had a similar but different error: Failed loading page:...HostNotFoundError
Basically, rotativa was trying to resolve the domain name from within the intranet, but this particular network does not allow you to access their own public facing sites using its bound domain name. Switching to .UrlAsAPdf and using the intranet IP address, fixed this.
Also test the PDF view/ page locally first, to see that it is doing what you want.

Interop.Excel 0x800A03EC - Out of memory error code 7

I am trying to cycle through a excel workbook and copy paste values over the top
of each sheet within that workbook. But I am running into a memory issue on line:
ws.select(true), when going to the next sheet.
Errors encountered:
Exception from HRESULT: 0x800A03EC:
and when I go to close out of the workbook at this point excel throws:
Out of memory (Error 7)
Additional information:
File size 3mb, 20 tabs and lots of database formulae reading from olap database TM1.
Microsoft office 2007
The code I am running is below. Is there a more efficient way of running it that may prevent the Out of Memory Error OR is this something different??
Any help would be much appreciated!
#
public bool wbCopyValueOnly(string workBook)
{
Workbook wb = excel.ActiveWorkbook;
Worksheet ws;
Range rng;
int WS_Count = wb.Sheets.Count;
for (int i = 0; i < WS_Count; i++)
{
try
{
ws = wb.Sheets[i + 1];
ws.Activate();
ws.Select(true);
//ws.Select(Type.Missing);
//ws.Cells.Select();
ws.UsedRange.Select();
//ws.Cells.Copy();
ws.UsedRange.Copy(Type.Missing);
ws.UsedRange.PasteSpecial(Excel.XlPasteType.xlPasteValues, Excel.XlPasteSpecialOperation.xlPasteSpecialOperationNone, false, false);
// select of range to get around memory issue
excel.Application.CutCopyMode = (Excel.XlCutCopyMode)0;
//rng = ws.get_Range("A1");
//rng.Select();
NAR(ws);
}
catch (System.Runtime.InteropServices.COMException err)
{
cLogging.write(LogLevel.Error, err.Message);
Debug.Print(err.Message);
return false;
}
}
NAR(wb);
return true;
}
private void NAR(object o)
{
try
{
while (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0) ;
}
catch { }
finally
{
o = null;
}
}
I have a program that copies from up to 100 tabs back to the first summary page and I found that using .Copy() caused several problems. Especially if your program runs for a length of time; the current user cannot use the copy-paste function without strange results. I recommend using variables to store what you need and then write to the intended range. Recording Macros is invaluable if you need to change the format of the range.
ws.Activate();
ws.Select(true);
ws.UsedRange.Select();
I think these code isn't necessary.
You can record a Marco to learn how to modify your code.

Runtime Error - Export Excel using C# from IIS

When I run on debugging mode on my local machine, there is no problems. I can export to excel...
private void ExportToExcel(string str)
{
_Excel.Application oXL;
_Excel.Workbook oWB;
_Excel.Worksheet oSheet;
_Excel.Range oRange;
// Start Excel and get Application object.
oXL = new _Excel.Application();
// Set some properties
oXL.Visible = true;
oXL.DisplayAlerts = false;
// Get a new workbook.
oWB = oXL.Workbooks.Add(Missing.Value);
// Get the active sheet
oSheet = (_Excel.Worksheet)oWB.ActiveSheet;
oSheet.Name = "PO_Status";
// Process the DataTable
int rowCount = 1;
foreach (DataRow dr in dtStatus(str).Rows)
{
rowCount += 1;
for (int i = 1; i < dtStatus(str).Columns.Count + 1; i++)
{
// Add the header the first time through
if (rowCount == 2)
{
oSheet.Cells[1, i] = dtStatus(str).Columns[i - 1].ColumnName;
}
oSheet.Cells[rowCount, i] = dr[i - 1].ToString();
}
}
// Resize the columns
oRange = oSheet.get_Range(oSheet.Cells[1, 1],
oSheet.Cells[rowCount, dtStatus(str).Columns.Count]);
oRange.EntireColumn.AutoFit();
try
{
// Save the sheet and close
oSheet = null;
oRange = null;
oWB.SaveAs("POStatus.xls", _Excel.XlFileFormat.xlWorkbookNormal,
Missing.Value, Missing.Value, Missing.Value, Missing.Value,
_Excel.XlSaveAsAccessMode.xlExclusive,
Missing.Value, Missing.Value, Missing.Value,
Missing.Value, Missing.Value);
//oWB.Close(Missing.Value, Missing.Value, Missing.Value);
//oWB = null;
//oXL.Quit();
// Clean up
// NOTE: When in release mode, this does the trick
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
catch (Exception ex)
{
Session["error"] = ex.Message;
Response.Redirect("MessageBoard.aspx");
}
}
private DataTable dtStatus(string str)
{
DataTable dt = new DataTable();
SqlCommand cmd = new SqlCommand(#"Select " + str + ""
+ " From tbl_RFI Full Join"
+ " tbl_RFQ On tbl_RFI.RFINo = tbl_RFQ.RFINo Full Join"
+ " tbl_NNB On tbl_RFQ.RFQNo = tbl_NNB.RFQNo Full Join"
+ " tbl_PO On tbl_PO.NNBNo = tbl_NNB.NNBNo"
+ " Where tbl_RFI.JobNo = '" + ddlJobNo.SelectedValue.ToString().Trim() + "'", connPMis);
SqlDataAdapter adp = new SqlDataAdapter(cmd);
adp.Fill(dt);
return dt;
}
}
But when I run on IIS, it's not working... I got error message like this
Runtime Error
Description: An application error occurred on the server. The current custom error settings for this application prevent the details of the application error from being viewed remotely (for security reasons). It could, however, be viewed by browsers running on the local server machine.
Details: To enable the details of this specific error message to be viewable on remote machines, please create a tag within a "web.config" configuration file located in the root directory of the current web application. This tag should then have its "mode" attribute set to "Off".
Notes: The current error page you are seeing can be replaced by a custom error page by modifying the "defaultRedirect" attribute of the application's configuration tag to point to a custom error page URL.
My Server is Windows Server 2008/ IIS7
thx for your help
Excel needs to be installed on the server for this to work.
An alternative way to see the full exception is if you have access to the server desktop, you can navigate to your page from the server and because it is local you'll get the full stack trace.
This is an expressly discouraged approach to working with Excel on the server, says Microsoft: http://support.microsoft.com/kb/257757. The preferred approach is to work with a library/dll that can read and/or manipulate xls and xlsx files without launching and automating some other application. There are free libraries, like NPOI, and commercial products like SpreadsheetGear and Aspose. You have a lot more options if you limit usage to xlsx.
If you DO use this interop approach:
a. You need to more carefully assign all items to variables for later cleanup. For example, each time you do oSheet.Cells[1, i] in a loop, you leak a cell reference.
b. Each resource that you assign must be cleaned up by calling Marshal.ReleaseComObject(theVariable) when you are through with it. THESE THINGS ARE NOT GARBAGE COLLECTED, so GC.Anything will have no effect.
c. Your try…catch redirects without cleaning up any resources that were acquired before the exception or closing Excel, which means every time an exception is encountered in this method, you are liable to have a phantom Excel instance running in the background. You'll probably need to use try…catch…finally and do all of your cleanup in the finally block.
go into your application and in your web.config and change your <customErrors element to mode="Off" and try again and post the real error message here. The other thing you can do is login to the IIS machine and run it there and see the full error message.
It could be be permissions in saving the excel file, or it could be an error launching excel but we need to see the error message here. Make sure that the location you are saving the file to has permissions to the Network Service account (or whatever account you happen to have your application running under as its app pool account in iis)
See the following link for many many other (better) ways of doing this.
Create Excel (.XLS and .XLSX) file from C#

Excel Interop: Quitting the Excel application instance makes my tests fail?

I want to encapsulate the use of Excel Interop to make it easier to use somehow in a reuseable library.
So far, I have written some tests that work good altogether, except that between each test, I force Excel to quite so that it does have handle on the test file no more in order to be able to delete.
Once I quit the application instance between after each of my tests, Excel seems to be no longer responding, causing Windows to display
"Excel has stopped working and is looking for a solution"
message. This message lasts a few seconds, meanwhile Excel is closing, causing the hang on the file to occur and my tests to throw an exception like
"Cannot access file because it is being used by another process..."
message. Otherwise, each of my tests run individually just fine!
Any clue on how to solve this issue?
Do I overuse the ApplicationClass.Quit() method?
Quitting Excel only once the testing is through with my tests causes the files created for the tests purpose not to be deleteable.
Thanks! =)
If you've made changes to the Workbook then could it be the "Do you wish to save changes?" dialog which is holding things up. You could try setting the _Workbook.Saved property to True prior to quitting the application. See here for details
I was having the same "Cannot access file because it is being used by another process..." issue.
I was saving the worksheet, what you need to do is save the work book. Here's a full example.
private void TestCreateExcel(IEnumerable<Sales1> data)
{
var excelApp = new Excel.Application();
var workBook = excelApp.Workbooks.Add();
Excel._Worksheet workSheet = excelApp.ActiveSheet;
workSheet.Cells[1, "A"] = "Title";
workSheet.Cells[1, "B"] = "Author(s)";
workSheet.Cells[1, "C"] = "Release Date";
workSheet.Cells[1, "D"] = "Total Books Sold";
workSheet.Cells[1, "E"] = "Last 30 Days Sales";
workSheet.Cells[1, "F"] = "Average Sales Per Month";
workSheet.Cells[1, "G"] = "Starting Advance";
workSheet.Cells[1, "H"] = "Current Advance";
int index = 1; //Keep track of the which row we're writing to.
foreach (var n in data)
{
index++;
workSheet.Cells[index, "A"] = n.Title;
workSheet.Cells[index, "B"] = n.Author;
workSheet.Cells[index, "C"] = n.ReleaseDate.ToShortDateString();
workSheet.Cells[index, "D"] = n.TotalBooksSold;
workSheet.Cells[index, "E"] = n.Last30DaysSales;
workSheet.Cells[index, "F"] = n.AverageSalesPerMonth;
workSheet.Cells[index, "G"] = n.StartingAdvance;
workSheet.Cells[index, "H"] = n.CurrentAdvance;
}
workBook.SaveAs(Server.MapPath(filePath + fileName));
excelApp.Quit();
}

Categories