1

I must be missing something here, but I seem to have a List whose items are getting caught as null, even after I've checked and confirmed they were not.

My unit tests for my ASP.NET MVC project were throwing a NullReferenceException on a foreach loop, but I couldn't find any reason for it, so I threw a handful of checks into my code. To my surprise, the check statements don't catch any null values, but the exception persists. Here's the relevant code:

[HttpPost]
[ValidateAntiForgeryToken]
public PartialViewResult CreateSimilar(int rebateId, List<AddressInput> addresses, bool recdResults = false)
{
    List<RebateHeader> newRebates = new List<RebateHeader>();
    RebateHeader entity = null;

    int newId = -1;

    if (!recdResults)
    {
        var repo = _db as HeaderRepository;
        List<PotentialDuplicate> allDups = new List<PotentialDuplicate>();

        //A few checks for null objects to illustrate my point-------
        if (addresses == null)
            throw new ApplicationException("Addresses was null"); //Not thrown
        else
            System.Console.WriteLine("Addresses was not null"); //This line is hit

        foreach (AddressInput address in addresses)
        {
            if (address == null)
                throw new ApplicationException("Address was null"); //Not thrown
            else
                System.Console.WriteLine("Address was not null"); //This line is hit
        }

        var test = addresses[0];
        System.Console.WriteLine(test.City); //This line returns a value
        System.Console.WriteLine(test.State); //This line returns a value
        //End checks---------------------------------------------------

        foreach (AddressInput address in addresses) //NullReferenceException THROWN HERE
        {
            List<PotentialDuplicate> dups = repo.GetDuplicateAddresses(
                address.Address, address.City, address.State).ToList();
            if (dups.Count > 0)
            {
                allDups.AddRange(dups);
            }
        }

        if (allDups.Count > 0)
        {
            return PartialView("_AddressDialogPotentialDup", allDups);
        }
    }
    . . . //Additional code truncated
    return PartialView("_IndexNoPager", model);
}

I must be missing something here, but I'm not seeing it. Any ideas?

For further reference, here's the unit test that's failing:

[Test]
public void CreateSimilar_Adds_1_New_Record()
{
    EntryController controller = new EntryController(repository);
    List<AddressInput> addresses = new List<AddressInput> 
    {   
        new AddressInput 
    { 
        Address = "Duplicate St.", City = "Testville", State = "MN", 
        ClosingDate = null, Quarter = "115" 
    }
    };

    controller.CreateSimilar(1, addresses); //Unit test FAILS HERE

    Assert.AreEqual(4, repository.GetAll().Count());
    Assert.AreEqual(1, repository.Added.Count);
    Assert.AreEqual("Test Duplicate 1", repository.Added[0].Address);
}

UPDATE: In response to a comment below, here's my code for GetDuplicateAddresses:

public IEnumerable<PotentialDuplicate> GetDuplicateAddresses(
    string address, string city, string state)
{
    var result = new List<PotentialDuplicate>();

    using (SqlCommand cmd = new SqlCommand("dbo.GetDuplicateAddresses", (SqlConnection)this.Database.Connection))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@Address", address);
        cmd.Parameters.AddWithValue("@City", city);
        cmd.Parameters.AddWithValue("@State", state);

        cmd.Connection.Open();
        using (var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
        {
            while (reader.Read())
            {
                result.Add(new PotentialDuplicate
                {
                    OrigAddress = address,
                    RebateIdMatch = reader.GetInt32(0),
                    Address = reader.GetString(1),
                    MatchType = reader.GetString(2)
                });
            }

            return result;
        }
    }
}

And here's the stub I'm using in my unit test:

public IEnumerable<PotentialDuplicate> GetDuplicateAddresses(
    string address, string city, string state)
{
    var result = new List<PotentialDuplicate>();
    return result;
}
Jeff Rosenberg
  • 3,522
  • 1
  • 18
  • 38
  • Where does the unit test fails and why? – thepirat000 Feb 07 '15 at 02:45
  • I've edited my code block to make this more clear. It fails on the call to the controller, because it gets kicked out by the `NullReferenceException` that's thrown at the beginning of the `foreach` loop. – Jeff Rosenberg Feb 07 '15 at 02:47
  • On which `For..In` loop? – thepirat000 Feb 07 '15 at 02:48
  • Sorry, meant `foreach`. It happens at `foreach (AddressInput address in addresses)`, the second time. The first is just one I added as a check, expecting it to catch a null value there. – Jeff Rosenberg Feb 07 '15 at 02:49
  • Does it throws the NullReferenceException even if you remove the code inside the foreach? Also try with a normal `for` instead of the ForEach – thepirat000 Feb 07 '15 at 02:53
  • The normal `for` I tried earlier, and it didn't work, but commenting out the code inside the `foreach` seems to fix the exception. It seems that the code inside the loop may be the culprit. I didn't realize that was an option! – Jeff Rosenberg Feb 07 '15 at 02:58
  • 1
    Probably the GetDuplicateAddresses method is returning NULL, and then the .ToList() fails. – thepirat000 Feb 07 '15 at 03:09
  • Almost all cases of `NullReferenceException` are the same. Please see "[What is a NullReferenceException in .NET?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-in-net)" for some hints. – John Saunders Feb 07 '15 at 04:56

2 Answers2

1

I would check to see if "dups" is null before doing the dups.Count() > 0

Tim Southard
  • 604
  • 4
  • 16
  • The exception is raised at the beginning of the `foreach (AddressInput address in addresses)` loop. Would a null inside the loop cause the exception to be raised there? I wouldn't think so, but I could certainly be wrong, as I'm no c# expert. – Jeff Rosenberg Feb 07 '15 at 02:49
  • dups cannot be null. IEnumerable.ToList() will never return null – thepirat000 Feb 07 '15 at 02:50
  • It has happened to me before. – Tim Southard Feb 07 '15 at 02:51
  • Can you show us the repo.GetDuplicateAddresses() code please? The error could be in that method. – Tim Southard Feb 07 '15 at 02:55
  • Well, it turned out I hadn't implemented it in my unit tests! I'm implementing it now, but it doesn't seem to be fixing the problem. I'll add the code above. – Jeff Rosenberg Feb 07 '15 at 03:08
  • Your SQL is returning 3 columns of data right? If not the reader.Get** could blow up. – Tim Southard Feb 07 '15 at 03:21
  • Yes. I'm actually leaning towards this being a problem in my test, now. I don't run into any issues when running the code, just during testing. – Jeff Rosenberg Feb 07 '15 at 03:36
  • Thanks for all your help. I suspect your answer may be the right; I'll keep plugging away at it and mark it as the answer if it pans out, but it may take me a day or two. – Jeff Rosenberg Feb 07 '15 at 03:46
  • I keep staring at your test code and nothing really stands out. Good Luck! – Tim Southard Feb 07 '15 at 03:48
  • Possibly a stupid suggestion, but in your GetDuplicateAddresses() method, when running the test, does this.Database.Connection have a value?? – Tim Southard Feb 07 '15 at 04:05
0

As it turns out, the problem was with this cast:

var repo = _db as HeaderRepository;

I had to refactor some of my other code, and I changed this line slightly to raise an InvalidCastException if there's a similar issue in the future:

var repo = (IHeaderRepository)_db;

I hadn't even thought to check this, because the compiler was highlighting the foreach loop as the location of the exception. Thanks to Tim Southard and thepirat000 for pointing out that the code block inside the loop could cause the compiler to raise the exception.

Jeff Rosenberg
  • 3,522
  • 1
  • 18
  • 38