Can not check if an array is null - c#

i have the folloiwng action method inside my asp.net mvc application:-
public ActionResult CustomersDetails(long[] SelectRight)
{
if (SelectRight == null)
{
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
RedirectToAction("Index");
}
else
{
var selectedCustomers = new SelectedCustomers
{
Info = SelectRight.Select(GetAccount)
};
return View(selectedCustomers);
}
return View();
}
But if the SelectRight Array is empty then it will bypass the if (SelectRight == null) check and it will render the CustomerDetails view and raise an exception on the following code inside the view
#foreach (var item in Model.Info) {
<tr>
So how can i make the null check works fine?

You have to return the result of RedirectToAction(..).
public ActionResult CustomersDetails(long[] SelectRight)
{
if (SelectRight == null)
{
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
return RedirectToAction("Index");
}
else
{
'...

You can change the condition to the following one:
...
if (SelectRight == null || SelectRight.Length == 0)
...
That should help.
EDIT
The important thing to note about the code above is that in c#, the or operator || is short circuiting. It sees that the array is null (statement is true) and does NOT attempt to evaluate the second statement (SelectRight.Length == 0) so no NPE is thrown.

You could check that it isn't null, and doesn't have a length of zero.
if (SelectRight == null || SelectRight.Length == 0) {
ModelState.AddModelError("", "Unable to save changes...");
return RedirectToAction("Index");
}
Above if-statement would catch both null-values and empty arrays.

Related

C#: null warning even though it's not possible

Ok so here I have this function that can return a null value in some cases. However, even when testing if it is before, it still says it might be null.
My code:
if (Account.FindAccount(usernameInput) == null) { return; }
if (Account.FindAccount(usernameInput).password == "1234") // warning CS8602: Dereference of a possibly null reference
{
//Do stuff
}
Is that FindAccount operation guaranteed to be idempotent? The compiler has no such guarantee. What it returns in one call it might not return in another.
More to the point... If you believe it will always return the same result for the same input, why are you invoking it twice? Just invoke it once and store the result:
var account = Account.FindAccount(usernameInput);
if (account == null) { return; }
if (account.password == "1234")
{
//Do stuff
}

Transactions: IsolationLevel set to Serializable - is this correct?

Could you please help me out confirming/disconfirming my doubts using Serializable isolationlevel.
I want to make sure that I've chosen a proper IsolationLevel for the following method AddUserTournament. Whenever this transaction is being executed, I want to be 100% sure, that entity.seats is up-to-date - preventing any other transactions from adding users concurrently.
Can I implement this using a more loose IsolationLevel, or does this seems as the proper way?
public void AddUserTournament(Tournament entity, User user)
{
try
{
// Add the user to tournament. Do this with a snapshot-isolationlevel
using (var transaction = _dbContext.Database.BeginTransaction(System.Data.IsolationLevel.Serializable))
{
try
{
// Get all users and include their relations to tournament
entity =
_dbContext.Tournaments.Where(e => e.TournamentId == entity.TournamentId)
.Include(t => t.Users)
.FirstOrDefault();
// Get the user
user = _dbContext.Users.SingleOrDefault(e => e.UserId == user.UserId);
// Check if there are available seats in the tournament and if user exist amoung enrolled users
if (entity != null && entity.Seats > entity.Users.Count &&
entity.Users.All(e => user != null && e.UserId != user.UserId))
{
// Add user
entity?.Users.Add(user);
// Save changes
_dbContext.SaveChanges();
// Commit transaction
transaction.Commit();
}
}
catch (Exception)
{
transaction.Rollback();
}
}
}
catch (DbEntityValidationException ex)
{
throw new FaultException(new FormattedDbEntityValidationException(ex).Message);
}
}
I know this is not answering your question, but feel i should point out how to make it more readable.
Just showing how you could rewrite you 'if' into something readable.
//after you refactor it more you will see that this check is actually not needed.
if (entity != null)
{
//Called entity but represents a Tournament
//so the check is to see if the T has more seats than the current attending users
if(entity.Seats.Count > entity.Users.Count)
{
//this was to check if the user is already in the attending users
//if(entity.Users.All(e => user != null && e.UserId != user.UserId))
var userInSeats = entity.Users.Where(x=>x.UserId == user.UserId).SingleOrDefualt();
if(userInSeats == null )
{
// Add user
entity.Users.Add(user);
// Save changes
_dbContext.SaveChanges();
// Commit transaction
transaction.Commit();
}
}
}
you would then see that the null check is not needed as this method should not be able to be called with no entity... i would call things what they are unless you are using generics which you aint here.

delete azure table storage row without checking for existence

I've been using azure table storage for years, and I'm not sure what the "proper" way to do this is with the newest WindowsAzure.Storage library, version 5.0.1-preview (for use in a new ASP.NET 5 application):
Problem:
Given a partition key and row key, delete the row without checking for existence first, and without failing if it does not exist.
Current Solution: This code works... but the exception handling is confusing:
public async Task DeleteRowAsync(CloudTable table, string partition, string row)
{
var entity = new DynamicTableEntity(partition, row);
entity.ETag = "*";
var op = TableOperation.Delete(entity);
try
{
await table.ExecuteAsync(op);
}
catch (Exception ex)
{
var result = RequestResult.TranslateFromExceptionMessage(ex.Message);
if (result == null || result.HttpStatusCode != 404)
throw ex;
}
}
Questions:
The exception itself pointed me to this TranslateFromExceptionMessage method... I can't find a whole lot of information on that and WrappedStorageException (the type of the exception that is thrown). Is this some kind of new/preferred way to check for 404 errors on storage exceptions? Does anyone know if all storage exceptions will now use this, or do I need to write code to test and figure it out?
There is an InnerException of type StorageException. Presumably our older code that used StorageException.RequestInformation.HttpStatusCode could access this inner exception in the same way. Is that "OK", or is parsing these new XML error messages better or more robust somehow?
Is there a different approach altogether that I should be considering for this case?
If you are using the latest client (Azure.Data.Tables), the delete method automatically swallows 404 responses and does not throw. This approach avoids the need to write code that introduces race conditions (checking first before performing an operations) or having to handle this condition with a try/catch block.
If you want to know if the operation actually deleted a table or it didn't exist, you can inspect the Status property of the response.
Response response = await tableClient.DeleteAsync();
if (response.Status == (int)HttpStatusCode.NotFound)
{
// entity didn't exist)
}
The RequestResult.TranslateFromExceptionMessage method is now marked [Obsolete] and I wanted a way to ignore 404's myself.
Based on your tip to check out the RequestInformation.HttpStatusCode I came up with the following:
try
{
await table.ExecuteAsync(op);
}
catch (StorageException storEx)
{
if (storEx.RequestInformation.HttpStatusCode != 404)
{
throw;
}
}
There is a similar approach found in the AspNet WebHooks project when configured to use Azure Table Storage. Take a look at the Microsoft.Aspnet.WebHooks.custom.AzureStorage StorageManager class.
I'm not sure this adds much on top of what you'd already found, but they handle everything without throwing an exception and always return a status code so you can react to that as necessary.
One difference here is they pass in the table and the operation to a multi-purpose ExecuteAsync method, rather than having one specifically for delete, but that's just an implementation detail.
Relevant code from their example:
public async Task<TableResult> ExecuteAsync(CloudTable table, TableOperation operation)
{
if (table == null)
{
throw new ArgumentNullException(nameof(table));
}
if (operation == null)
{
throw new ArgumentNullException(nameof(operation));
}
try
{
var result = await table.ExecuteAsync(operation);
return result;
}
catch (Exception ex)
{
var errorMessage = GetStorageErrorMessage(ex);
var statusCode = GetStorageStatusCode(ex);
var message = string.Format(CultureInfo.CurrentCulture, AzureStorageResources.StorageManager_OperationFailed, statusCode, errorMessage);
_logger.Error(message, ex);
return new TableResult { HttpStatusCode = statusCode };
}
}
public string GetStorageErrorMessage(Exception ex)
{
if (ex is StorageException storageException && storageException.RequestInformation != null)
{
var status = storageException.RequestInformation.HttpStatusMessage != null ?
storageException.RequestInformation.HttpStatusMessage + " " :
string.Empty;
var errorCode = storageException.RequestInformation.ExtendedErrorInformation != null ?
"(" + storageException.RequestInformation.ExtendedErrorInformation.ErrorMessage + ")" :
string.Empty;
return status + errorCode;
}
else if (ex != null)
{
return ex.Message;
}
return string.Empty;
}
public int GetStorageStatusCode(Exception ex)
{
return ex is StorageException se && se.RequestInformation != null ? se.RequestInformation.HttpStatusCode : 500;
}

Why does the else statement not get executed if one of the bool parameters for if is null?

I have this code snippet here:
public void ReDrawParallelLines(string lineName, string viewType)
{
var referenceLineOne = GetLineParams(viewType + ReferenceEnum.One.ToString() + linename);
var referenceLineTwo = GetLineParams(viewType + ReferenceEnum.Two.ToString() + linename);
if (lineName == referenceLineOne.lineParams.lineName)
{
//Do certain action with referencelineone
}
else if (lineName == referenceLineTwo.lineParams.lineName)
{
//Do same action but with referencelinetwo
}
}
I noticed that if referenceLineOne is null but I have referenceLineTwo, the else statement never gets executed. I'm not sure why? Doesn't it work such that if the bool fails the if then continue to the else and it should pass for the else. It just skips the inside if statement and the else condition entirely because the referenceLineOne is null. Why and how can I correct this check?
Basically, I am passing a line name and I want to check to see if it's equal to one of two lines I get from the GetLineParams function.
Since referenceLineOne is null, you will get an exception, which is why it bypasses the else if and jumps somewhere else.
You should do null checking like this
if (referenceLineOne != null && lineName == referenceLineOne.lineParams.lineName)
{
//Do certain action with referencelineone
}
or this if you use c#6
if (lineName == referenceLineOne?.lineParams.lineName)
{
//Do certain action with referencelineone
}

Refactoring exceptions for workflow

I am currently refactoring an application which uses exceptions for logic flow. The code is difficult to read and maintain and makes a S.O.L.I.D fanboy like myself cry when reading it (not to mention the longest catch block I've ever seen in my career).
My question is what pattern(s) could you use to make it easier to maintain or how would you go about refactoring?
public void CallExternalServices(ICriteria criteria)
{
try
{
someResult = ExternalService1.SomeMethod(criteria);
}
catch (Service1Exception service1Exception)
{
if (criteria.SomeValue == "1")
{
if (service1Exception.InnerException != null
&& service1Exception.InnerException.InnerException != null
&& service1Exception.InnerException.InnerException is TargetSystemException)
{
TargetSystemException targetSystemException = (TargetSystemException)service1Exception.InnerException.InnerException;
if (targetSystemException.ErrorStatus.IsServiceDownForMaintenance())
{
// Call internal method to perform some action
SendNotification("Service down for maintenance.")
}
}
}
else if (criteria.SomeValue == "2")
{
if (service1Exception.InnerException != null
&& service1Exception.InnerException.InnerException != null
&& service1Exception.InnerException.InnerException is TargetSystemException)
{
TargetSystemException tx = (TargetSystemException)service1Exception.InnerException.InnerException;
if (targetSystemException.ErrorStatus.IsBusy())
{
// Call to some internal method to perform an action
SendDifferentNotification()
criteria.SetSomeFlagToBe = true;
try
{
someResult = ExternalService2.SomeOtherMethod(criteria);
}
catch (Service2Exception service2Exception)
{
if (service2Exception.InnerException != null
&& service2Exception.InnerException.InnerException != null
&& service2Exception.InnerException.InnerException is TargetSystemException)
{
TargetSystemException tx = (TargetSystemException)service1Exception.InnerException.InnerException;
if (targetSystemException.ErrorStatus.HasNumberOfDailyTransactionsBeenExceeded())
{
// Call internal method to perform some action
SendNotification("Number of daily transactions exceeded.")
}
}
else if (service2Exception.InnerException != null
&& service2Exception.InnerException.InnerException != null
&& service2Exception.InnerException.InnerException is FaultException)
{
FaultException faultException = service2Exception.InnerException.InnerException as FaultException;
if (faultException.Detail != null
&& faultException.Detail.FaultMessage.Equals("SomeValueToCheckAgainst", StringComparison.OrdinalIgnoreCase))
{
return someResult;
}
else
{
throw service2Exception;
}
}
else
{
throw service2Exception;
}
}
if (someResult != null)
{
// perform another action
SomeActionInvoker.ExecuteAcitonAgainst(someResult);
}
}
}
else if (service1Exception.InnerException != null
&& service1Exception.InnerException.InnerException != null
&& service1Exception.InnerException.InnerException is FaultException)
{
FaultException faultException = service1Exception.InnerException.InnerException as FaultException;
if (faultException.Detail != null
&& faultException.Detail.FaultMessage.Equals("SomeOtherValueToCheckAgainst", StringComparison.OrdinalIgnoreCase))
{
return someResult;
}
else
{
throw service1Exception;
}
}
else
{
throw service1Exception;
}
}
}
}
All in all I think you would be helped by breaking up some stuff into some helper methods. For example, you could extract your checks that look like this
if (<exception-instance>.InnerException != null &&
<exception-instance>.InnerException.InnerException != null &&
<exception-instance>.InnerException.InnerException is <exception-type>)
Into a boolean method; you call code like this at least 3 times by my cursory glance.
Also, I would recommend extracting that second top-level case into an error-handling method; and perhaps its nested if statements.
Check out Working Effectively with Legacy Code by Michael Feathers, particularly Chapter 22 (I Need to Change a Monster Method and I Can't Write Tests for It). There are a lot of great techniques in there for situations like yours. Personally, in cases like this I usually end up extracting methods from sections of the longer methods, and getting rid of local variables that are used throughout the method; these are almost always trouble.
Start by refactoring the method into multiple methods. You've got waaaaaay too many levels of indentation going on.
After that, consider if some of the new methods could be extracted into other objects, and use an IoC-style approach rather than a procedural one.
That's kind of a high level answer, but I'm tired and don't have the energy to actually rework the code myself :)

Categories