Index was outside the bounds of the array C# in unit test - c#

I input my QuaterDisplay as dummy data, but I get the error as below:
Index was outside the bounds of the array.
Code:
private string GetQuarterDisplay(DateTime dateKey)
{
return ((AvailabilityDS.IntelTimeRow[])mAvailabilityDS.Time.Select("DateKey = '"
+ dateKey + "'"))[0].QuarterDisplay; //error occur here
}
internal void PropagateModelStartQuarter()
{
object[] args = new object[0];
m_privateObject.Invoke("PropagateModelStartQuarter", new System.Type[0], args);
}

I am pretty sure this is the line in error:
((AvailabilityDS.IntelTimeRow[])mAvailabilityDS.Time.Select("DateKey = '"
+ dateKey + "'"))[0]
I guess there is no item on that time stamp, resulting in an empty array. If you try to access the first item in an empty array, that is the error you get.
If you use LINQ, you could use FirstOrDefault, which will not fail when there is no item. Instead, it will return the default value. In this case null:
var availability = ((AvailabilityDS.IntelTimeRow[])mAvailabilityDS.Time.Select("DateKey = '"
+ dateKey + "'")).FirstOrDefault();
and then:
if (availability != null)
{
return availability.QuarterDisplay;
}
else
{
// return a default value, or throw an exception
return null;
}

This means that there is no row in mAvailabilityDS table Time with specified DateKey string representation.
I would replace this with strongly typed LINQ solution:
private string GetQuarterDisplay(DateTime dateKey)
{
return ((AvailabilityDS.IntelTimeRow[])mAvailabilityDS.Time.Select()
.Where(x => x.DateKey == dateKey)
.Select(x => x.QuarterDisplay)
.FirstOrDefault();
}
EDIT
The main problem is that you are searching your rows by string representation of date/time object which is dependant on the current culture used.
This string representation does not match standard ISO format datetime (like 2009-11-03 00:00:00) that is used in DataTable internals to filter values.
If you really want to use not-strongly-typed approach, convert datet/time object to string using invariant culture.
private string GetQuarterDisplay(DateTime dateKey)
{
return ((AvailabilityDS.IntelTimeRow[])mAvailabilityDS.Time.Select("DateKey = '"
+ dateKey.ToString(DateTimeFormatInfo.InvariantInfo) + "'"))[0].QuarterDisplay;
}

why don't you check for null?
private string GetQuarterDisplay(DateTime dateKey)
{
var availabilityDS = (AvailabilityDS.IntelTimeRow[])mAvailabilityDS
if(availabilityDS != null)
{
var time = availabilityDS.Time;
if(time != null)
{
var elements = availabilityDS.Select('"+ dateKey + "'");
if(elements.Any())
{
return elements[0].QuarterDisplay;
}
}
}
return null;
}

You are assuming that the Select class returns an item. If it's an empty array then you are indexing into an empty array. Use something like:
private string GetQuarterDisplay(DateTime dateKey)
{
var times =((AvailabilityDS.IntelTimeRow[])mAvailabilityDS.Time.Select("DateKey = '"
+ dateKey + "'"));
if (times.Length > 0)
{
return times[0].QuarterDisplay;
}
return null; // Or whatever
}
Alternatively use if (!times.Any())...

DataTable.Select didn't return any rows, therefore you get the mentioned exception if you try to access a non-existing row.
You may want to use LINQ instead which makes it much more readable:
var timeRow = mAvailabilityDS.Time.FirstOrDefault(x => x.DateKey == dateKey);
if(timeRow != null)
return timeRow.QuarterDisplay;
else
return null;
Maybe you don't find any rows because there is a time portion that you want to ignore. Then you can use the Date property of DateTime:
var timeRow = mAvailabilityDS.Time.FirstOrDefault(x => x.DateKey.Date == dateKey.Date);

Related

Foreach string occurrence

So I would like to read out all occurrences in C# in one string and work with it. Means I need the position of the part string, but I don't know how. Example:
The main string can look like this:
Currently there are %count{"only_groups":"1, 2, 3","ignore_channels":"1, 2, 3"}% supporters online, %count{"ignore_channels":"1, 2, 3","querys":"false"}% of them are afk. These are the active supporters: %list{"querys":"false","only_groups":"1, 2, 3"}%
Contentwise this string makes no sense, but I think you can understand what I mean by these strings. There are also more possible variables besides %count% and %list%
Now I want to keep all these variables and replace something instead.
I already have the following code, but it would only replace one variable and it would only recognize the %count% variable if it is completely lower case:
int pFrom = channel_name.IndexOf("%count{") + "%count{".Length;
int pTo = channel_name.LastIndexOf("}%");
string result = channel_name.Substring(pFrom, pTo - pFrom);
Logger.Info(result);
string json2 = #"{" + result + "}";
JObject o2 = JObject.Parse(json2);
foreach (JProperty property in o2.Properties())
{
var pname = property.Name;
if (pname == "only_groups")
{
only_groups = property.Value.ToString();
}
else if (pname == "ignore_groups")
{
ignore_groups = property.Value.ToString();
}
else if (pname == "only_channels")
{
only_channels = property.Value.ToString();
}
else if (pname == "ignore_channels")
{
ignore_channels = property.Value.ToString();
}
else if (pname == "away")
{
away = property.Value.ToString();
}
else if (pname == "querys")
{
query = property.Value.ToString();
}
}
var serverVar = (await fullClient.GetServerVariables()).Value;
if (query.Equals("only"))
{
channel_name = "User online: " + serverVar.QueriesOnline;
}
else if (query.Equals("ignore"))
{
channel_name = "User online: " + (serverVar.ClientsOnline - serverVar.QueriesOnline);
}
else
{
channel_name = "User online: " + serverVar.ClientsOnline;
}
I hope people understand what I'm about to do. My English is not the best
Use Regex.Matches() to get a list of all occurences.
This pattern will find all variables including configuration json:
(?s)%.*?%
Then you just need to extract the 2 parts out of the matched value.
This will find only the variable name within the matched value:
(?s)(?<=%).+?(?=({|%))
This will find the JSON configuration within the matched value if there is any:
(?s){.*}
Only caveat is you can't use % character anywhere in text outside of variables.

How to use list values globally in asp.net c#

I want to use the below list globally in my aspx page whose name is lstUMSGroupDetails. Currently I am getting its value from a function.
I want to use that list values in other functions too. SO how should I make it global.
its code is below
private void Get_AuthenticateUser_Ums(string strUName)
{
string strCurrentGroupName = "";
int intCurrentGroupID = 0;
try
{
if (!string.IsNullOrEmpty(strUName))
{
List<IPColoBilling.App_Code.UMS.UMSGroupDetails> lstUMSGroupDetails = null;
List<IPColoBilling.App_Code.UMS.UMSLocationDetails> lstUMSLocationDetails = null;
objGetUMS.GetUMSGroups(strUserName, out strCurrentGroupName, out intCurrentGroupID, out lstUMSLocationDetails, out lstUMSGroupDetails);
if (strCurrentGroupName != "" && intCurrentGroupID != 0)
{
strCurrentGrp = strCurrentGroupName;
intCurrentGrpId = intCurrentGroupID;
}
else
{
Response.Redirect("~/NotAuthorize.aspx", false);
}
}
}
catch (Exception ex)
{
string strErrorMsg = ex.Message.ToString() + " " + "StackTrace :" + ex.StackTrace.ToString();
CommonDB.WriteLog("ERROR:" + strErrorMsg, ConfigurationManager.AppSettings["IPCOLO_LOG"].ToString());
}
You can store it in Session.
Session["lstUMSGroupDetails"] = lstUMSGroupDetails;
Then you can get this by.
List<IPColoBilling.App_Code.UMS.UMSGroupDetails> lstUMSGroupDetails = (List<IPColoBilling.App_Code.UMS.UMSGroupDetails>)Session["lstUMSGroupDetails"];
For more information please see MSDN Reference.
Could you not assign it to a slot in the Session Dictionary?
For example:
var myList = new List<int>();
Session["groups"] = myList;

Null Reference Exception when trying to store an array

So I'm trying to store fields from a text file into an array. But when I reach the line
data = record.Trim().Split('*');
I get an error saying "Object reference not set to an instance of an object."
public bool matchCustomer(string accountID, string record)
{
String[] data = new String[5];
data = null;
data = record.Trim().Split('*');
this.accountNumber = data[0];
if (accountID == this.accountNumber)
{
return true;
}
else
{
return false;
}
}
Here is where the method is called:
public bool findCustomer(string accountNumber)
{
string record = Global.currentFile.getNextRecord(ref endOfFile);
bool okay = Global.customer.matchCustomer(accountNumber, record);
return okay;
}
Here is getNextRecord:
public string getNextRecord(ref Boolean endOfFileFlag)
{
string nextRecord;
endOfFileFlag = false;
nextRecord = reader.ReadLine();
if (nextRecord == null)
{
endOfFileFlag = true;
}
else
{
recordReadCount += 1;
} // end if
return (nextRecord);
} // end getNextRecord
First, you can simplify your code by replacing:
String[] data = new String[5];
data = null;
data = record.Trim().Split('*');
with just a single line:
string[] data = record.Trim().Split('*');
This is a correct statement, because you don't know the max index (elements) of the string[] array returning by Split() function.
Second, make sure that record!=null, and also it has a string containing "*" characters used as delimiter in Split() function.
Let's look at this line of code
data = record.Trim().Split('*');
If a NullReferenceException occurred here, that means you must be calling a method on a null object. In this case, the only possible object is record.
Now we know what is null, but why is it null? Let's look at this method:
public bool findCustomer(string accountNumber)
{
string record = Global.currentFile.getNextRecord(ref endOfFile);
bool okay = Global.customer.matchCustomer(accountNumber, record);
return okay;
}
Apparently you are using the return value of getNextRecord to call matchCustomer. This means that getNextRecord must return be returning null! So let's find out why getNextRecord returns null:
public string getNextRecord(ref Boolean endOfFileFlag)
{
string nextRecord;
endOfFileFlag = false;
nextRecord = reader.ReadLine();
if (nextRecord == null)
{
endOfFileFlag = true;
}
else
{
recordReadCount += 1;
} // end if
return (nextRecord);
} // end getNextRecord
If the method return nextRecord, that means nextRecord is null. And how did you get nextRecord? reader.ReadLine!
So the ultimate reason why record is null is that reader.ReadLine is null.
To avoid this exception, you need to first check whether record is null, then call the method on it:
if (record != null) {
data = record.Trim().Split('*');
} else {
// do other stuff
}
In C# 6, this can be simplified to
data = record?.Trim().Split('*');
If record is null, data will be null too!
Also, note that this code is redundant:
String[] data = new String[5];
data = null;
You are creating a bunch of strings and then setting the array to null. What's the point? So you can just remove that, and change the next line to:
string[] data = record?.Trim().Split('*');

Invalid Cast DateTime?

I have a class with the following code
public cCase(string pCaseNo, string pMode)
{
if (pMode == "new")
{
this._caseNo = Validate_CaseNo(pCaseNo);
}
if (pMode == "existing")
{
try
{
int intValidatedCaseNo = Validate_CaseNo(pCaseNo);
string sqlText = "SELECT * FROM tblCases WHERE CaseNo = #CaseNo;";
string strConnection = cConnectionString.BuildConnectionString();
SqlConnection linkToDB = new SqlConnection(strConnection);
linkToDB.Open();
SqlCommand sqlCom = new SqlCommand(sqlText, linkToDB);
sqlCom.Parameters.Add("#CaseNo", SqlDbType.Int);
sqlCom.Parameters["#CaseNo"].Value = intValidatedCaseNo;
SqlDataReader caseReader = sqlCom.ExecuteReader();
if (caseReader.HasRows)
while (caseReader.Read())
{
this._claimant = caseReader["Claimant"].ToString();
this._defendant = caseReader["Defendant"].ToString();
this._caseType = caseReader["CaseType"].ToString();
this._occupation = caseReader["Occupation"].ToString();
this._doa = (DateTime?)caseReader["DOA"];
this._dateClosed = (DateTime?)caseReader["DateClosed"];
this._dateSettled = (DateTime?)caseReader["DateSettled"];
this._dateInstructed = (DateTime?)caseReader["DateInstructed"];
this._status = caseReader["Status"].ToString();
this._instructionType = caseReader["InstructionType"].ToString();
this._feeEstimate = (decimal?)caseReader["FeeEstimate"];
this._amountClaimed = (decimal?)caseReader["AmountClaimed"];
this._amountSettled = (decimal?)caseReader["AmountSettled"];
this._caseManager = caseReader["CaseManager"].ToString();
}
caseReader.Close();
linkToDB.Close();
linkToDB.Dispose();
}
catch (Exception eX)
{
throw new Exception("Error finding case" + Environment.NewLine + eX.Message);
}
}
}
However the Datetime? casts fail with an 'Invalid Cast'.
I've checked the SQL database and the field is storing valid dates
So I cant work out why, as I extract info via the DataReader into my app, the datetime fields are causing an Invalid Cast.
Please help.
You're going to want to change the line that reads:
this._doa = (DateTime?)caseReader["DOA"];
to:
if (caseReader["DOA"] != DBNull.Value)
this._doa.Value = (DateTime)caseReader["DOA"];
As well as all similar lines.
DBNull values cannot be casted from Nullable types.
Your DateTime fields probably hold a DBNull value which you cannot convert directly.
However, I'd use an extension method on your DataReader for convinience.
public static class DataReaderExtensions
{
public static DateTime? ReadNullableDateTime(this IDataReader reader, string column)
{
return reader.IsDBNull(column) ? (DateTime?)null : reader.GetDateTime(column);
}
}
// Usage
this._dateInstructed = CaseReader.ReadNullableDateTime("DateInstructed");
You should use
DateTime.TryParse Method
this not throw exception, like
var mydate =(DateTime)datetimeString
or
var mydate =DateTime.Parse(datetimeString)
does!!!
Try with the following code part
this._doa = (caseReader["DOA"] == DBNull.Value ? DBNull.Value : Convert.ToDateTime(caseReader["DOA"]);
Try to Convert Date Time as
this._doa = Convert.ToDateTime(caseReader["DOA"]);
I often deal with DBNull.Value...
So I use this method that will return the value of the object or the default value of the given value type if object's value is DBNull.Value.
public static object GetValueOrDefault(object value, Type type)
{
if (value != DBNull.Value)
return value;
if (type.IsValueType == false)
return null;
Array array = Array.CreateInstance(type, 1);
return array.GetValue(0);
}
Usage:
GetValueOrDefault(dataRecord.GetValue(fieldIndex), dataRecord.GetFieldType(fieldIndex)

WMI is being too slow

Is there a way to limit the number of entries WMI retrieves with a WQL statement?
I say this because running a query to retrieve all Win32_NTLogEvent instances is taking forever! All I really need are the most recent events (for about a week, or 2000 entries)
Here's a snippet of the code I'm using to get the log data. Other queries such as Win32_Processor are nice and quick.
if (Configuration.OnlyErrorLogs)
{
// If Information logs should be suppressed, only get events where event type is not 3
WMIDataTemp1 = DataRetriever.GetWMIData("Win32_NTLogEvent", "EventType<>3");
}
else
{
WMIDataTemp1 = DataRetriever.GetWMIData("Win32_NTLogEvent");
}
foreach (ManagementObject Object in WMIDataTemp1)
{
this.Log.Add(new Log(Object));
}
And the functions to get WMI data are as follows:
public static ManagementObject[] GetWMIData(string wmiClass) { return GetWMIData(wmiClass, "", "CIMV2"); }
public static ManagementObject[] GetWMIData(string wmiClass, string whereClause) { return GetWMIData(wmiClass, whereClause, "CIMV2"); }
public static ManagementObject[] GetWMIData(string wmiClass, string whereClause, string nameSpace)
{
try
{
// If a where clause has been set, prepare the clause to add to the query string
if (whereClause != "")
{
whereClause = " WHERE " + whereClause;
}
// Create a search query
string query = "SELECT * FROM " + wmiClass + whereClause;
ManagementObjectSearcher wmiSearcher = new ManagementObjectSearcher("root\\" + nameSpace, query);
ManagementObjectCollection matches = wmiSearcher.Get();
// Create an array to hold the matches
ManagementObject[] matchArray = new ManagementObject[matches.Count];
// If matches found, copy to output
if(matches.Count > 0)
{
// Copy the search matches into this array
matches.CopyTo(matchArray, 0);
}
// Return array
return matchArray;
}
catch (Exception e)
{
ErrorDialogue errorReporter = new ErrorDialogue(e);
return null;
}
}
Where each Log gets stored:
public class Log
{
public string Category = "N/A";
public string DateTime = "N/A";
public UInt16 ID = 0;
public string Level = "N/A";
public string Message = "N/A";
public string Source = "N/A";
public Log() { }
public Log(ManagementObject wmiLogEvent)
{
this.GetInfo(wmiLogEvent);
}
public void GetInfo(ManagementObject wmiLogEvent)
{
try
{
this.Category = DataRetriever.GetValue(wmiLogEvent, "CategoryString");
this.DateTime = DataRetriever.GetValue(wmiLogEvent, "TimeGenerated");
this.ID = DataRetriever.GetValueUInt16(wmiLogEvent, "EventIdentifier");
this.Level = DataRetriever.ConvertEventType(DataRetriever.GetValueUInt16(wmiLogEvent, "CategoryString"));
this.Message = DataRetriever.GetValue(wmiLogEvent, "Message");
this.Source = DataRetriever.GetValue(wmiLogEvent, "SourceName");
}
catch (Exception e)
{
ErrorDialogue errorReporter = new ErrorDialogue(e);
}
}
}
One option is to use a WHERE clause to specify the range of the entries you want...
For example you could use TimeGenerated in the WHERE clause to specify a time-based range...
Another option is to set BlockSize accordingly when creating ManagementObjectSearcher.
You could use that to specify that you want 2000 entries per call for example - together with an ORDER BY TimeGenerated DESC this should give a nice result.
Speed is not a strong suit for WMI. It tends to be quite memory intensive. However, the question has been addressed and there are a few things you can do. Check out Why are my queries taking such a long time to complete? from Microsoft TechNet.
Now using the System.Diagnostics.EventLog class as a faster alternative. Much more beneficial to the program compared to WMI.
http://msdn.microsoft.com/en-us/library/system.diagnostics.eventlog.aspx

Categories

Resources