Reading From Excel File - Cells with Values Show Null - c#

I have written some code that reads every row in an excel file (for two specific columns) which I will be using later to execute an update SQL Query for each of the rows with a value.
I have displayed these values in a listbox, and I am getting far more nulls than expected when comparing with the stock codes in the excel file.
I have tried changing the formatting of the excel file, but this did not make any difference. There are rows where there definitely are stock codes at that position, but when the program does the cell comparison the program identifies them as nulls when they actually have values.
Does anyone know what the problem is with my code?
private void btnStockCodes_Click(object sender, RoutedEventArgs e)
{
string file = #"\\amn-fs-01\users$\Shanel\Desktop\Stock Codes.xlsx";
Microsoft.Office.Interop.Excel.Application ExcelApp = new Microsoft.Office.Interop.Excel.Application();
Workbook ExcelWorkbook = ExcelApp.Workbooks.Open(file);
Worksheet ews = ExcelApp.ActiveWorkbook.Sheets[1];
Microsoft.Office.Interop.Excel.Range usedRange = ews.UsedRange;
int TotalCounter = 0;
string StockCode = "";
string ReserveID = "";
int nullcounter = 0;
int foundcounter = 0;
foreach (Microsoft.Office.Interop.Excel.Range row in usedRange.Rows)
{
StockCode = "";
ReserveID = "";
TotalCounter = TotalCounter + 1;
if (row.Cells[TotalCounter,7].Value == null)
{
Listbox1.Items.Add(TotalCounter + " null");
nullcounter = nullcounter + 1;
}
else
{
StockCode = row.Cells[TotalCounter,7].Value.ToString();
ReserveID = row.Cells[TotalCounter, 3].Value.ToString();
Listbox1.Items.Add(TotalCounter + " " + StockCode + " " + ReserveID);
foundcounter = foundcounter + 1;
}
}
txtTotal1.Text = foundcounter.ToString() + " Found";
txtTotal2.Text = nullcounter.ToString() + " Null Values";
txtTotal3.Text = TotalCounter.ToString() + " Total Records";
}

I would not trust that Worksheet.UsedRange always works correctly, sometimes it contains more cells than it should, or less. My suggestion is to read all rows in worksheet, while you have any values. Once there are no more values, just stop reading it.
And if you have too many rows, you can read all values at the same time into an array, like here and work with the array.

Thanks for your contributions, I have resolved the error!
It occurs in the row.Cells[TotalCounter,7].Value.ToString()
It should have been row.Cells[7].Value.ToString()
There was no need for me to specify a row index as that's taken care of in the Foreach loop. I will look into alternative ways of writing the code as Worksheet.UsedRange might not work in all cases as Alex suggested.

Related

C# - Double spaces in DB field causing unwanted newlines when writing to a text file

Let me preface this by saying I have never really coded in C# (I'm a Python programmer) and I coded in C++ back in college a little bit
I have an SSIS package that has several C# script components (found the script online somewhere) that essentially reads data from a database and writes it to a text file. When I started data validation I noticed my file had about 3500 more rows in it than the database table itself. After writing a python script to compare the data, I realized that we have a database field called "REMARKS" that has been appended to several times. Whenever it is appended it apparently causes a double space (hitting space bar twice).
When the script encounters this double white space issue it will write to a new line. I do NOT want it to do this. I need all those remarks to stay in its original field. Please see my script below.
public void Main()
{
// TODO: Add your code here
string datetime = DateTime.Now.ToString("yyyyMMddHHmmss");
string date = DateTime.Now.ToString("yyyyMMdd");
try
{
//Declare Variables
string FileNamePart = Dts.Variables["$Project::pvarWorkorderFlatFileNamePart"].Value.ToString();
string DestinationFolder = Dts.Variables["$Project::pvarDestinationFolder"].Value.ToString();
string TableName = Dts.Variables["$Project::pvarWorkorderTableName"].Value.ToString();
string FileDelimiter = Dts.Variables["$Project::pvarFileDelimiter"].Value.ToString();
string FileExtension = Dts.Variables["$Project::pvarFileExtension"].Value.ToString();
//USE ADO.NET Connection from SSIS Package to get data from table
SqlConnection myADONETConnection = new SqlConnection();
myADONETConnection = (SqlConnection)(Dts.Connections["DB_CNXN"].AcquireConnection(Dts.Transaction) as SqlConnection);
//Read data from table or view to data table
string query = "SELECT * FROM " + TableName;
SqlCommand cmd = new SqlCommand(query, myADONETConnection);
//myADONETConnection.Open();
DataTable d_table = new DataTable();
d_table.Load(cmd.ExecuteReader());
myADONETConnection.Close();
string FileFullPath = DestinationFolder + "\\" + FileNamePart + "_" + date + FileExtension;
StreamWriter sw = null;
sw = new StreamWriter(FileFullPath, false);
// Write the Header Row to File
int ColumnCount = d_table.Columns.Count;
for (int ic = 0; ic < ColumnCount; ic++)
{
sw.Write(d_table.Columns[ic]);
if (ic < ColumnCount - 1)
{
sw.Write(FileDelimiter);
}
}
sw.Write(sw.NewLine);
// Write All Rows to the File
foreach (DataRow dr in d_table.Rows)
{
for (int ir = 0; ir < ColumnCount; ir++)
{
if (!Convert.IsDBNull(dr[ir]))
{
sw.Write(dr[ir].ToString());
}
if (ir < ColumnCount - 1)
{
sw.Write(FileDelimiter);
}
}
sw.Write(sw.NewLine);
}
sw.Close();
Dts.TaskResult = (int)ScriptResults.Success;
}
catch (Exception exception)
{
// Create Log File for Errors
using (StreamWriter sw = File.CreateText(Dts.Variables["$Project::pvarLogFolder"].Value.ToString() + "\\" +
"ErrorLog_" + datetime + ".log"))
{
sw.WriteLine(exception.ToString());
Dts.TaskResult = (int)ScriptResults.Failure;
}
}
Dts.TaskResult = (int)ScriptResults.Success;
}
#region ScriptResults declaration
/// <summary>
/// This enum provides a convenient shorthand within the scope of this class for setting the
/// result of the script.
///
/// This code was generated automatically.
/// </summary>
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
#endregion
}
}
So the database table row might look something like this:
tip|date |remarks |completed|device_id
n |2018-01-03|1st att 9/7/17 2nd att 9/12/17 3rd att 11/7/17 need code |Y |123
(Notice double spaces in remarks field between each of those entries including after the last one)
When the script runs and outputs to the file this is what it would look like (file is pipe (|) delimitted):
Line 1:n|2018-01-03|
Line 2:1st att 9/7/17
Line 3:2nd att 9/12/17
Line 4:3rd att 11/7/17 need code
Line 5:
Line 6:|Y|1234
I just need the script to take the rows as-is and keep everything on one line like this:
Line 1:n|2018-01-03|1st att 9/7/17 2nd att 9/12/17 3rd att 11/7/17 need code |Y|1234
I am pulling the data from a SQL database and if there are no double spaces in the remarks field, then the script functions as intended.
If someone could PLEASE help I would be forever grateful! Thank you in advance!
I was mistaken that it was double spaces, as it actually was CRLF (\r\n) that was in the database. So taking what #Ali Maleki provided above, I used this to solve my issue:
sw.Write((dr[ir].ToString()).Replace("\r\n","_"));
Thanks for your guys' help!
Find this line in your code : sw.Write(dr[ir].ToString());
Replace with : sw.Write((dr[ir].ToString()).Replace(' ', '_'));
Result :
Line 1:n|2018-01-03|1st_att_9/7/17__2nd_att_9/12/17__3rd_att_11/7/17_need code__|Y|1234

Exporting to excel export converts special characters to HTML codes

I need to export Date, Title and Description to excel file, right now i am facing two issue with the export of excel file.
one special characters such as '," an other characters turn into ‘ & etc....
All these issue are with the Description column, which stored text in HTML format. Below is the example of text in various formats
Actual Text
The ‘ Golf Season Opening’ marked the official opening of the at Golf Club, Season to start on March 10, 2018.
Text Stored in Database MS SQL SERVER
The ‘Golf Season Opening ‘ marked the official opening of the at Golf Club& Season to start on March 10& 2018.
Text exported to Excel
The ‘Golf Season Opening ‘ marked the official opening of the at Golf Club& Season to start on March 10& 2018.
I am using below code to create excel file but i am facing above issue.
How can i store text without being decoding text is excel should be store in text format & all special characters show properly without any issue
var wb = new XLWorkbook();
var ws = wb.Worksheets.Add("Calendar");
DataTable dt = ds.Tables[0];
var rowIndex = 2; // 1 = header row
foreach (DataRow row in dt.Rows)
{
ws.Cell("A" + rowIndex).Value = row["Year"];
ws.Cell("B" + rowIndex).Value = row["Title"];
string noHTML = Regex.Replace(row["Description"].ToString(), #"<[^>]+>| ", "").Trim();
string noHTMLNormalised = Regex.Replace(noHTML, #"\s{2,}", " ");
ws.Cell("C" + rowIndex).Value = noHTMLNormalised;
rowIndex++;
}
//// From worksheet
var rngTable = ws.Range("A1:C" + rowIndex);
var rngHeader = ws.Range("A1:C1");
var rngYear = ws.Range("A2:A" + rowIndex);
//var rngDate = ws.Range("B2:B" + rowIndex);
var rngTitle = ws.Range("B2:D" + rowIndex);
var rngDesc = ws.Range("C2:C" + rowIndex);
rngHeader.Style.Fill.SetBackgroundColor(XLColor.CoolGrey);
rngHeader.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
rngHeader.Style.Font.Bold = true;
rngHeader.Style.Font.FontColor = XLColor.White;
// rngYear.Style.Fill.SetBackgroundColor(XLColor.CoolGrey);
rngYear.Style.Font.Bold = true;
rngYear.Style.Font.FontColor = XLColor.Black;
rngYear.Style.Alignment.Indent = 1;
//rngDate.Style.DateFormat.Format = "MM/DD/YYYY";
//rngDate.Style.Alignment.Indent = 10;
rngDesc.Style.Alignment.SetWrapText();
ws.RangeUsed().Style.Border.OutsideBorder = XLBorderStyleValues.Thick;
var col3 = ws.Column("C");
//col3.Style.Fill.BackgroundColor = XLColor.Red;
col3.Width = 100;
ws.Columns().AdjustToContents();
string fileName;
fileName = "Golf_Calendat.xlsx";
wb.SaveAs(HttpContext.Current.Server.MapPath("../excel/" + fileName));
Any help to fixed the above issue and also if we we can wrap the text in description column and if row can take the auto height based on the wrapped text.
Just to mention i am using using Excel = Microsoft.Office.Interop.Excel; for excel export
you can replace it in a string
str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
Solved Both issue with following code
First by using HTML HttpUtility.HtmlDecode
string htmlDec = HttpUtility.HtmlDecode(row["Description"].ToString());
and text wrap issue with ws.Column(2).AdjustToContents(5, 7);
string htmlEnc = HttpUtility.HtmlEncode(row["Description"].ToString());
string htmlDec = HttpUtility.HtmlDecode(row["Description"].ToString());
string noHTML = Regex.Replace(htmlDec, #"<[^>]+>| ", "").Trim();
string noHTMLNormalised = Regex.Replace(noHTML, #"\s{2,}", " ");
ws.Cell("C" + rowIndex).Value = noHTMLNormalised;

C# generated worksheet is read-only and locked

I have a problem with opening and saving Excel file which my C# program generated. Every time I made some changes manually and try to save the Excel file, the popup message ask me to save a copy of this file because it is read-only. It is ok but annoying. My excel file is produced by my C# program. Here is my code snippet:
/**
* Save the matched data
* */
public void saveMatch(List<String> saveB, List<String> saveG, Excel.Worksheet bellSheet, Excel.Worksheet GSMSheet, String fileurl, String mCode, String prioName,int sNumber = 0)
{
object misValue = System.Reflection.Missing.Value;
Excel.Application newApp = new Excel.Application();
Excel.Workbook newWB = newApp.Workbooks.Add(misValue);
Excel.Worksheet newWS = newWB.Worksheets.get_Item(1);
String colName1 = bSheet.get_Range("A1").Cells.Value;
String colName2 = GSheet.get_Range("A1").Cells.Value;
int i = 2;//start copy from row two of the Sheet, row one is the column name
newWS.Cells[1, 2] = colName2;//copy the column name
newWS.Cells[1, 1] = colName1;//copy the column name
//Copy excatly matching data
for (int j = 0; j < saveB.Count; j++)
{
newWS.Cells[i, 1] = saveB[j];
newWS.Cells[i, 2] = saveG[j];
//Console.WriteLine(saveG[j] + " : " + saveB[j]);
i++;
}
if (sNumber==0)
{
if (prioName.Equals("None"))
{
newWB.SaveAs(fileurl + #"\MdResults_" +"None_"+ mCode + ".xlsx");
}
else
{
newWB.SaveAs(fileurl + #"\MdResults_" + prioName+"_"+mCode + ".xlsx");
}
}
else
{
if (prioName.Equals("None"))
{
newWB.SaveAs(fileurl + #"\MdResults_" + "None_"+mCode + "_" + sNumber + ".xlsx");
}
else
{
newWB.SaveAs(fileurl + #"\MdResults_" +prioName + "_"+mCode + "_" +sNumber + ".xlsx");
}
}
newWB.Close(0);
newApp.Quit();
}
Program runs ok and I can open the saved Excel file successfully. I just wondering am I missing something in the C# code or I just need to modify something in Excel file itself? I want the excel file which my program generated can be modified and saved as normal without a popup message to ask me to save as a copy. Thanks for the help.
If you don't close newApp, an Excel process will stick around in memory and keep your file locked.
Check your task list to confirm this is happening.
Try adding the following after saving your file
newApp.Close(0);
newApp.Quit();

reader.Read() only read once even when there are multiple rows to read

I have the code
while (reader.Read())
{
if (reader[incrementer]!=DBNull.Value){
string playerToInform = reader.GetString(incrementer).ToString();
string informClientMessage = "ULG=" + clientIP + ","; //User Left Game
byte[] informClientsMessage = new byte[informClientMessage.Length];
informClientsMessage = Encoding.ASCII.GetBytes(informClientMessage);
playerEndPoint = new IPEndPoint(IPAddress.Parse(playerToInform), 8001);
clientSocket.SendTo(informClientsMessage, playerEndPoint);
}
incrementer++;
}
which after debugging my code i see contains 4 entries. However only the first result is ever read from the reader. After the first iteration to find if the result returned is null or not the loop starts again and immediately finishes even though there are three more rows to read.
Any ideas as to why this may be occuring would be apprechiated.
edit - this is the reader i used
OleDbDataReader reader = dBConn.DataSelect("SELECT player1_IP, player2_IP, player3_IP, player4_IP FROM running_games WHERE game_name = '" + gameName + "'", updateGameList);
The indexer of DbDataReader (DataReader is something else) or a database specific subclass, returns the value of the specified (by index or name).
While DbDataReader.Read() moves to the next row.
If you want to apply the same logic to multiple columns you need to loop over the columns, and the rows:
while (db.Read()) {
for (var colIdx = 0; colIdx < columnCount. ++colIdx) {
if (!db.IsDbNll(colIdx)) {
string value = db.GetString(colIdx);
// Process value
}
}
}
You're incrementing "incrementer" as if that was the row number, but a DataReader holds only one row per Read() and the indexing is for the field number.
Use this:
while (reader.Read())
{
for(int colNum = 0; colNum < 4; colNum++)
{
if (reader[colNum]!=DBNull.Value)
{
string playerToInform = reader.GetString(colNum).ToString();
string informClientMessage = "ULG=" + clientIP + ","; //User Left Game
byte[] informClientsMessage = new byte[informClientMessage.Length];
informClientsMessage = Encoding.ASCII.GetBytes(informClientMessage);
playerEndPoint = new IPEndPoint(IPAddress.Parse(playerToInform), 8001);
clientSocket.SendTo(informClientsMessage, playerEndPoint);
}
}
}
Incrementer is unnecessary. reader.Read() advances to next record and returns false if there are no more rows.
Check documentation on msdn

While Reading data from a .xlsx file

string Code = "";
if (fileUp.HasFile)
{
string Path = fileUp.PostedFile.FileName;
// initialize the Excel Application class
ApplicationClass app = new ApplicationClass();
// create the workbook object by opening the excel file.
Workbook workBook = app.Workbooks.Open(Path, 0, true, 5, "", "", true,
XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
// Get The Active Worksheet Using Sheet Name Or Active Sheet
Worksheet workSheet = (Worksheet)workBook.ActiveSheet;
int index = 0;
// This row,column index should be changed as per your need.
// that is which cell in the excel you are interesting to read.
object rowIndex = 2;
object colIndex1 = 1;
object colIndex2 = 2;
object colIndex3 = 3;
object colIndex4 = 4;
object colIndex5 = 5;
object colIndex6 = 6;
object colIndex7 = 7;
try
{
while (((Range)workSheet.Cells[rowIndex, colIndex1]).Value2 != null)
{
rowIndex = 2 + index;
//string QuestionCode = (index + 1).ToString();
string QuestionCode = ((Range)workSheet.Cells[rowIndex, colIndex1]).Value2.ToString();
string QuestionText = ((Range)workSheet.Cells[rowIndex, colIndex2]).Value2.ToString();
string CorrectAnswer = ((Range)workSheet.Cells[rowIndex, colIndex3]).Value2.ToString();
string ChoiceA = ((Range)workSheet.Cells[rowIndex, colIndex4]).Value2.ToString();
string ChoiceB = ((Range)workSheet.Cells[rowIndex, colIndex5]).Value2.ToString();
string ChoiceC = ((Range)workSheet.Cells[rowIndex, colIndex6]).Value2.ToString();
string ChoiceD = ((Range)workSheet.Cells[rowIndex, colIndex7]).Value2.ToString();
// string ChoiceE = ((Excel.Range)workSheet.Cells[rowIndex, colIndex7]).Value2.ToString();
newQuestionElement = new XElement("Question");
XElement optionElement = new XElement(QuestionElement.Option);
questionType = ddlQusType.SelectedValue.ToByte();
if (!string.IsNullOrEmpty(QuestionText))
newQuestionElement.Add(new XElement(QuestionElement.QuestionText, QuestionText));
else
{
//lblMessage.Text = "Missing question in Qus No.: " + i;
break;
}
newQuestionElement.Add(new XElement(QuestionElement.QuestionType, questionType));
//newQuestionElement.Add(new XElement(QuestionElement.Randomize, chbRandomizeChoice.Checked));
newQuestionElement.Add(new XElement(QuestionElement.Answer, CorrectAnswer));
if (ChoiceA.Trim() != string.Empty)
optionElement.Add(new XElement("A", ChoiceA));
if (ChoiceB.Trim() != string.Empty)
optionElement.Add(new XElement("B", ChoiceB));
if (ChoiceC.Trim() != string.Empty)
optionElement.Add(new XElement("C", ChoiceC));
if (ChoiceD.Trim() != string.Empty)
optionElement.Add(new XElement("D", ChoiceD));
newQuestionElement.Add(optionElement);
index++;
saveData(QuestionCode.ToString());
I am using this code to retrieve the data from .xlsx file.
But if the file has any special characters in it, it is showing it as different, like so
The set S = {1,2,33……….12} is to be partitioned into three sets
A,B,C of equal size. Thus, `A U B U C = S,`
The set S = {1,2,33……….12} is to be partitioned into three sets
A,B,C of equal size. Thus, `A È B È C = S,`
Looks like an encoding issue.
I use to have this issue after reading Excel into a data table and then serializing the data table to a file.
Every time I would read the data back in from the serialized file, some symbols would be replaced with funny A's and E's.
I discovered the problem was with the encoding I was using. I then started to store excel data using Unicode encoding and have never encounter another symbol problem with Excel data again.
I hope this helps...

Categories