Linq Select Statement help needed - NullReferenceException after using FirstOrDefault - c#

I have a LINQ statement handling the Login process. It works fine when passed valid username and password combinations. However when I test on invalid credentials, I get a NullReferenceException error on the line below indicated by <<<---------------- Need some help on proper handling of invalid credentials please?
public int _accountID;
public int _securityLevelID;
public void GetLoginInfo(string EmailAddress, string Password)
{
LoginItem l = null;
{
try
{
using (RootsDataContext RDC = new RootsDataContext())
l = (from a in RDC.DBLogIns
where a.EmailAddress == EmailAddress
&& a.Password == Password
&& a.IsActive == 1
select new LoginItem
{
AccountIDFK = a.AccountIDFK,
SecurityLevelIDFK = a.SecurtityLevelIDFK,
}).FirstOrDefault();
_accountID = (int)l.AccountIDFK; <<<----------------
_securityLevelID = (int)l.SecurityLevelIDFK;
if (_accountID < 1 || _accountID == null)
{
lbl_LoginStatus.Text = "Invalid";
}
}
catch (Exception ex)
{
string error = ex.Message;
}
if (_accountID > 0)
{
if (_accountID == 1 && _securityLevelID == 1) // [Quentin]
{
Response.Redirect("~/AccountsMaster.aspx");
}
if (_accountID > 1 && _securityLevelID == 2) // [Companies]
{
Response.Redirect("~/CompanyMaster.aspx");
}
if (_accountID > 1 && _securityLevelID == 3) // [Branch]
{
Response.Redirect("~/BranchMaster.Aspx");
}
if (_accountID > 1 && _securityLevelID == 4) // [Clients]
{
Response.Redirect("~/Home.aspx");
}
}
}
}

By saying
// ...
}).FirstOrDefault();
You will either get an DBLogIn object if a match is found, or null if it is not.
You will need to check for null before accessing the property AccountIDFK and SecurityLevelIDFK:
// ... }).FirstOrDefault();
if (l != null)
{
_accountID = (int)l.AccountIDFK;
_securityLevelID = (int)l.SecurityLevelIDFK;
}
Some other points to consider:
You shouldn't store passwords directly in the database. A more secure approach is to store hashed (and potentially salted) passwords in the database, and then to find the user (by EmailAddress and Active = 1), and then compare the hashes of what the user typed, and what is stored in the DB.
This code swallows exceptions - this makes diagnosing problems a nightmare:
catch (Exception ex)
{
string error = ex.Message;
}
Don't make fields public (public int _accountID;) - Make them private if they are not used externally, or convert them to (autogenerated) Properties if they are externally visible from your class.

FirstOrDefault method will return null if there's no DBLogIn records match the criteria you give, so you need to check if l is null first before accessing (int)l.AccountIDFK. Moreover, it looks like lbl_LoginStatus.Text = "Invalid"; should be done when l is null, so you need to remove if (_accountID < 1 || _accountID == null) block and change your code as follows:
if (l != null)
{
_accountID = (int)l.AccountIDFK;
_securityLevelID = (int)l.SecurityLevelIDFK;
}
else
{
// logic when l is null
lbl_LoginStatus.Text = "Invalid";
}
Alternatively you can also use C# Ternary Operator to check if l is null
_accountID = l != null ? (int)l.AccountIDFK : 0;
_securityLevelID = l != null ? (int)l.SecurityLevelIDFK : 0;
if (_accountID < 1)
{
lbl_LoginStatus.Text = "Invalid";
}

You should check for null value in 'l' before using it.
if(l!=null)
{
_accountID = (int)l.AccountIDFK;
_securityLevelID = (int)l.SecurityLevelIDFK;
}
else
{
lbl_LoginStatus.Text = "Invalid";
}

Linq FirstOrDefault returns null if there is no item in the list matching your query.So if you get null in your code means that user login is invalid.
public int _accountID;
public int _securityLevelID;
public void GetLoginInfo(string EmailAddress, string Password)
{
LoginItem l = null;
{
try
{
using (RootsDataContext RDC = new RootsDataContext())
l = (from a in RDC.DBLogIns
where a.EmailAddress == EmailAddress
&& a.Password == Password
&& a.IsActive == 1
select new LoginItem
{
AccountIDFK = a.AccountIDFK,
SecurityLevelIDFK = a.SecurtityLevelIDFK,
}).FirstOrDefault();
if(l==null || _accountID < 1 || _accountID == null)
{
lbl_LoginStatus.Text = "Invalid";
Response.Redirect("~/InvalidCredentials.aspx"); // redirect to invalid login page.
}
else
{
_accountID = (int)l.AccountIDFK;
_securityLevelID = (int)l.SecurityLevelIDFK;
}
}
catch (Exception ex)
{
string error = ex.Message;
}
if (_accountID > 0)
{
if (_accountID == 1 && _securityLevelID == 1) // [Quentin]
{
Response.Redirect("~/AccountsMaster.aspx");
}
if (_accountID > 1 && _securityLevelID == 2) // [Companies]
{
Response.Redirect("~/CompanyMaster.aspx");
}
if (_accountID > 1 && _securityLevelID == 3) // [Branch]
{
Response.Redirect("~/BranchMaster.Aspx");
}
if (_accountID > 1 && _securityLevelID == 4) // [Clients]
{
Response.Redirect("~/Home.aspx");
}
}
}
}

You should have a check for LoginItem's default value null, and if its null (in case of invalid credentials) then do whatever you want.

Related

Cosmos DB - Some records failing to insert

We have a recursive function we are using to bulk insert records into Cosmos.
While running a long migration to insert many records it appears that some records failed to insert but we have been unable to see why from the logging we have.
My assumption is a certain type of status code is not being retried when it should be or something is failing silently.
Can anyone advise what might be causing records to fail without being logged/being retried?
AllowBulkExecution = true is set when creating the container that is passed in to the code below.
public async Task<bool> TryBulkInsertAsync<T>(List<T> audits, int retryAttempts, TimeSpan retryDelay, int currentAttempt = 0, Container container = null) where T : BaseCosmosModel
{
if (currentAttempt > retryAttempts)
{
_logger.LogError($"Failed number of max retries ${retryAttempts}");
return false;
}
if (container == null)
{
container = _cosmosContainerFactory.BuildCosmosContainer<T>();
}
var attemptAudits = audits.Select(a => new CosmosInsertAttempt<T>
{
Audit = a,
RunningTask = container.CreateItemAsync(a)
}).ToList();
try
{
await Task.WhenAll(attemptAudits.Select(a => a.RunningTask));
var failedAudits = attemptAudits.Where(a =>
a.RunningTask.Result.StatusCode == HttpStatusCode.TooManyRequests ||
a.RunningTask.Result.StatusCode == HttpStatusCode.PreconditionFailed ||
a.RunningTask.Result.StatusCode == HttpStatusCode.RequestTimeout ||
a.RunningTask.Result.StatusCode == HttpStatusCode.ServiceUnavailable
).Select(a => a.Audit).ToList();
var nonRetryableAudits = attemptAudits.Where(a =>
!failedAudits.Contains(a.Audit) && (a.RunningTask.Result.StatusCode < (HttpStatusCode) 200 ||
a.RunningTask.Result.StatusCode > (HttpStatusCode) 299));
foreach (var audit in nonRetryableAudits)
{
_logger.LogError("Audit failed to bulk insert with non-retryable status code {cosmosAuditInsert}", audit.Audit);
}
if (failedAudits.Count > 0)
{
_logger.LogError("Retrying bulk insert from incorrect status code but no error, count: {retrySize}", failedAudits.Count);
return await TryBulkInsertAsync(failedAudits, retryAttempts, retryDelay, currentAttempt + 1, container);
}
return true;
}
catch (Exception)
{
await Task.Delay(retryDelay);
var failedAuditsWithException = attemptAudits
.Where(a => a.RunningTask.Exception != null)
.Select(a => a.Audit).ToList();
var failedAuditsWithBadStatusCode = attemptAudits.Where(a =>
(
a.RunningTask.Exception == null && a.RunningTask.Result != null &&
(a.RunningTask.Result.StatusCode == HttpStatusCode.TooManyRequests ||
a.RunningTask.Result.StatusCode == HttpStatusCode.PreconditionFailed ||
a.RunningTask.Result.StatusCode == HttpStatusCode.RequestTimeout ||
a.RunningTask.Result.StatusCode == HttpStatusCode.ServiceUnavailable)
)).Select(a => a.Audit).ToList();
if (failedAuditsWithBadStatusCode.Any())
{
_logger.LogError("Retrying bulk insert from incorrect status code but no error (some have exceptions), count: {retrySize}", failedAuditsWithBadStatusCode.Count);
}
var failedAudits = failedAuditsWithException.Concat(failedAuditsWithBadStatusCode).ToList();
var nonRetryableAudits = attemptAudits.Where(a =>
!failedAudits.Contains(a.Audit) && a.RunningTask.Exception == null && (a.RunningTask.Result.StatusCode < (HttpStatusCode)200 ||
a.RunningTask.Result.StatusCode > (HttpStatusCode)299));
foreach (var audit in nonRetryableAudits)
{
_logger.LogError("Audit failed to bulk insert with non-retryable status code {cosmosAuditInsert}", audit.Audit);
}
if (failedAudits.Count > 0)
{
_logger.LogError("Retrying bulk insert {failedAuditCount}", failedAudits.Count);
return await TryBulkInsertAsync(failedAudits, retryAttempts, retryDelay, currentAttempt + 1, container);
}
return true;
}
}

Return error message from a void method in C#

I'm currently trying to get my method to return an error message if a condition isn't valid. But I am uncertain how to go about this in a void method.
I have a method that looks like this
[HttpPost]
[ValidateAntiForgeryToken]
[Audit]
public void AddUnits(int so_id, int site_id, int[] addItem_id, int[] addItem_qty, int[] addItem_disc)
{
// Loop however many times is necessary to iterate through the largest array
for (int i = 0; i < Math.Max(Math.Max(addItem_id.Length, addComp_id.Length), addPart_id.Length); i++)
{
foreach (SODetails sod in db.SalesOrders.Find(so_id).SalesDetails)
{
if (i < addItem_id.Length && addItem_qty[i] != 0 && sod.ItemID == addItem_id[i] && addItem_id[i] != 365 && addItem_id[i] != 410)
{
sod.item_qty += addItem_qty[i];
sod.item_discount = addItem_disc[i];
addItem_id[i] = 0;
addItem_qty[i] = 0;
addItem_disc[i] = 0;
}
}
db.SaveChanges();
if(i < addItem_qty.Length && addItem_qty[i] != 0)
{
SODetails sODetails = new SODetails
{
SalesOrderID = so_id,
SiteID = site_id
};
// Only add a unit to the SODetails object if it's not null and has an id and quanitity specified
if(i < addItem_id.Length && addItem_id[i] != 0 && addItem_qty[i] != 0)
{
sODetails.ItemID = addItem_id[i];
sODetails.item_qty = addItem_qty[i];
sODetails.item_discount = addItem_disc[i];
}
if (sODetails.SiteID == 0)
sODetails.SiteID = null;
SalesOrder SO = db.SalesOrders.Find(sODetails.SalesOrderID);
SODetails salesOrderDetails = db.SODetails.Add(sODetails);
salesOrderDetails.SalesOrder = SO;
Item SO_Item = db.Items.Find(sODetails.ItemID);
Component SO_Component = db.Components.Find(sODetails.ComponentID);
Part SO_Part = db.Parts.Find(sODetails.PartID);
if (SO_Item != null)
{
if (SO.OrderType == SOType.OffSiteInventory && sODetails.InventorySite == "Main Inventory" && SO_Item.On_Hand < salesOrderDetails.item_qty)
{
ModelState.AddModelError(string.Empty, "Not enough stock in inventory");
//TempData["SalesOrderMessage"] = SO_Item.SalesOrderMessage;
}
sODetails.item_qty = sODetails.item_qty == null ? 0 : sODetails.item_qty;
int qtyOrdered = sODetails.item_qty == null ? 0 : (int)sODetails.item_qty;
salesOrderDetails.dynamicItem_qty = qtyOrdered;
if (SO_Item.SalesOrderMessage != null)
TempData["SalesOrderMessage"] = SO_Item.SalesOrderMessage;
}
db.SODetails.Add(sODetails);
}
}
db.SaveChanges();
}
Here is the part of the code where I am doing the validation check
if (SO.OrderType == SOType.OffSiteInventory && sODetails.InventorySite == "Main Inventory" && SO_Item.On_Hand < salesOrderDetails.item_qty)
{
ModelState.AddModelError(string.Empty, "Not enough stock in inventory");
//TempData["SalesOrderMessage"] = SO_Item.SalesOrderMessage;
}
If the condition is valid I want it to return to the screen with an error message showing up. But with the method being Void, I don't know how I can make it do this, or I don't know if it is even possible.
You could create a specific exception class that you can throw in your void function. You then handle this exception in the calling function.
class NotEnoughStockException : Exception {}
Then in your method:
If no stock ...
throw new NotEnoughStockException();
In the calling method
try {
call the stock method
} catch NotEnoughStockException {
whatever you want to do
}
Create a wrapper function that will call your stock function. You do try catch in that new function and return an error message. Your Ajax should call the new function.

Filter data from datatable for one of columns in asp.net

I have a datatable which fetches some records. So there is one column name as UPDATED_STATUS. In that column either Pre Hoto or Post Hoto value will come.
So what I want is, Either any one of those values should be their in that column then only the it should move ahead otherwise it should prompt alert as
Either Pre Hoto or Post Hoto can be their
Below is sample image for reference
Below is the code for getting the datatable with the UPDATED_STATUS column
if (strFlag == "")
{
dtStatus = GET_STATUS_FROM_SAPID_FOR_HOTO(dtExcelRows.Rows[i]["Current SAPID"].ToString());
if (dtStatus == null && dtStatus.Rows.Count < 0)
{
ClientScript.RegisterStartupScript(Page.GetType(), "erroralert", "alert('Status cannot be blank for SAP ID entered');", true);
}
else
{
dtExcelRows.Rows[i]["UPDATED_STATUS"] = dtStatus.Rows[0][1].ToString();
dtExcelRows.AcceptChanges();
}
}
Your current check (if (dtStatus == null && dtStatus.Rows.Count < 0)) is wrong:
when dtStatus is null, you continue checking dtStatus.Rows, which throws a nullref exception (you just found out that it was null);
Rows.Count is never less than zero.
Try if (dtStatus == null || dtStatus.Rows.Count == 0) to check whether there is no status at all (it is null) or no status rows (count is zero). The || will prevent checking for dtStatus.Rows when it was found that dtStatus is null.
&& means that both sides must be true at the same time.
|| means that at least of the sides must be true (both true is also fine).
Both don't evaluate the second test when the first already decided the outcome (false && whatever is always false, true || whatever is always true)
Are you looking for like this !
foreach (DataRow row in dtStatus.Rows)
{
if (string.IsNullOrEmpty(Convert.ToString(row["UPDATED_STATUS"])) ||
(Convert.ToString(row["UPDATED_STATUS"]).ToLower() != "pre hoto" &&
Convert.ToString(row["UPDATED_STATUS"]).ToLower() != "post hoto"))
{
ClientScript.RegisterStartupScript(Page.GetType(), "erroralert", "alert('Status cannot be blank for SAP ID entered');", true);
break;
}
else { }
}
I have got a way to get this done.. Here I go
if (strFlag == "")
{
dtStatus = GET_STATUS_FROM_SAPID_FOR_HOTO(dtExcelRows.Rows[i]["Current SAPID"].ToString());
if (dtStatus == null && dtStatus.Rows.Count < 0)
{
ClientScript.RegisterStartupScript(Page.GetType(), "erroralert", "alert('Status cannot be blank for SAP ID entered');", true);
}
else
{
dtExcelRows.Rows[i]["UPDATED_STATUS"] = dtStatus.Rows[0][1].ToString();
dtExcelRows.AcceptChanges();
}
}
}
DataTable dtGetHotoPre = null;
var rows = dtExcelRows.AsEnumerable().Where(x => x.Field<string>("UPDATED_STATUS") == "PRE HOTO");
if (rows.Any())
{
dtGetHotoPre = rows.CopyToDataTable();
}
DataTable dtGetHotoPost = null;
var rowsPost = dtExcelRows.AsEnumerable().Where(x => x.Field<string>("UPDATED_STATUS") == "POST HOTO");
if (rowsPost.Any())
{
dtGetHotoPost = rowsPost.CopyToDataTable();
}
string strFlagStatus = "";
if (dtGetHotoPre != null)
{
if (dtGetHotoPost != null)
{
strFlagStatus = "No Process";
}
else
{
strFlagStatus = "Process";
grdDvHoto.DataSource = dtGetHotoPost;
}
}
else
{
if (dtGetHotoPost != null)
{
strFlagStatus = "Process";
grdDvHoto.DataSource = dtGetHotoPre;
}
else
{
strFlagStatus = "No Process";
}
}
// if(dtGetHotoPre != null && dtGetHotoPost != null)
if (strFlagStatus == "No Process")
{
ClientScript.RegisterStartupScript(Page.GetType(), "erroralert", "alert('The sites contains both Pre and Post Hoto Status, so it cannot be uploaded');", true);
}
else
{
// will move ahead.
grdDvHoto.DataBind();
}

Due to LINQ Retrieving of Record data's i have this error: NullReferenceException was unhandled by user code

private void getUserLoginDepartment(string AccessID, string UserPROFid)
{
try
{
DBWPAccountRecordsDataContext DBACCOUNT = new DBWPAccountRecordsDataContext();
var query = (from i in DBACCOUNT.WP_UserAccessPorts
join
z in DBACCOUNT.WP_Departments on i.AccessPortID equals z.Dept_ID
where i.AccessPortID == AccessID && i.ProfileUser_ID == UserPROFid
select new
{
PORT1 = i.AccessPoint1,
PORT2 = i.AccessPoint2,
PORT3 = i.AccessPoint3,
PORT4 = i.AccessPoint4,
DEPT = z.Dept_DESC,
DEPTPORT = z.Dept_PortNo
}).FirstOrDefault();
if (query.PORT1.ToString() != null || query.PORT1.ToString() != string.Empty)
{ Session["Port1"] = query.PORT1; }
else { Session["Port1"] = ""; }
if (query.PORT2.ToString() != null || query.PORT2.ToString() != string.Empty)
{ Session["Port2"] = query.PORT2; }
else { Session["Port2"] = ""; }
if (query.PORT3.ToString() != null || query.PORT3.ToString() != string.Empty)
{ Session["Port3"] = query.PORT3; }
else { Session["Port3"] = ""; }
if (query.PORT4.ToString() != null || query.PORT4.ToString() != string.Empty)
{ Session["Port4"] = query.PORT4; }
else { Session["Port4"] = ""; }
}
finally
{
}
}
The Error occures when i reach break point 1st IF Statement the record on my database shows that its not empty which its value is "WebAdmin" but then suppost to be it should pick it up and store it to the Session["PORT1"] that i have made is there something i missed or i'm doing it wrong on my linq Query. NOTE:*This is an ASP.NET C# Application
EDIT 10/2/2013 0420PM:
It's still an Error After using that method sir.
1) you should check query for null when you use FirstOrDefault
2) you need to check each PORTX for null
3) use string.IsNullOrEmpty( ) to check if the string of PORTX is null
var query = ( ... ).FirstOrDefault( );
if( query != null )
{
if( query.PORT1 != null && !string.IsNullOrEmpty( query.PORT1.ToString( ) ) )
{
}
else { ... }
}
You have to check query.PORT1 for null before calling ToString on it, you can use String.IsNullOrEmpty to check both conditions. Before checking query.PORT1 you need to check if query is null or not. You also need to use && instead of or operator as || will cause the right side of or operator to be evaluated if left is false and on right side calling ToString on null will again through exception.
if (query != null && query.PORT1 != null && query.PORT1.ToString() != string.Empty)
{ Session["Port1"] = query.PORT1; }
Using IsNullOrEmpty
if(query != null && !String.IsNullOrEmpty(query.PORT1))
{
Session["Port1"] = query.PORT1;
}

avoid Row not found or changed error

I have banners on a site. When banner showed then I increment field in DB.
This is code:
public Banner GetBanner(CategoryBanner type)
{
var banners = Database.Banners.Where(b => b.IsPublish.Value &&
b.Category.Value == (int)type &&
b.PeriodShowCountAlready < b.PeriodShowCount || b.IsPublish.Value && b.Category.Value == (int)type &&
b.ShowNext < DateTime.Now);
var count = banners.Count();
if (count != 0)
{
var skip = new Random().Next(banners.Count() - 1);
Banner banner = banners.Skip(skip).FirstOrDefault();
if (banner != null)
{
UpdatePeriodShowCountAlready(banner); // problem is inside this method
if (banner.ShowStart == null)
UpdateShowStartAndEnd(banner);
return banner;
}
}
return null;
}
private void UpdatePeriodShowCountAlready(Banner banner)
{
try
{
if (banner != null)
{
banner.PeriodShowCountAlready++;
if (banner.PeriodShowCountAlready >= banner.PeriodShowCount && banner.ShowNext < DateTime.Now)
{
banner.PeriodShowCountAlready = 0;
banner.ShowStart = null;
banner.ShowNext = null;
}
Database.SubmitChanges();
}
}
catch (Exception ex)
{
ErrorLog.GetDefault(null).Log(new Error(ex));
}
}
And, I get the following error:
System.Data.Linq.ChangeConflictException
Row not found or changed.
This error is simple to reproduce:hold down the F5 is enough for a few seconds.
I understand why this error is occur, but how to rewrite my code properly?
Thanks.

Categories