0

I have the following model class inside my asp.net mvc web application:

public class SecurityRoleGroupAssign
{
    public  IEnumerable<TechnologyType> TechnologyType {get; set;}
    public  IEnumerable<PermisionLevel> PermisionLevel {get; set;}
    public SecurityRole SecurityRole { get; set; }
    public Nullable<int> rackPermisionLevel { get; set; }
    public Nullable<int> serverPermisionLevel { get; set; }
    public Nullable<int> routerPermisionLevel { get; set; }
    public Nullable<int> virtualMachinePermisionLevel { get; set; }
    public Nullable<int>  switchPermisionLevel { get; set; }
}

But when I tried to populate this class I got a Null Exception:-

public SecurityRoleGroupAssign populateSecurityRolePermisionLevelAssign(int RoleID)
{
    SecurityRoleGroupAssign c = new SecurityRoleGroupAssign
    {
        SecurityRole = FindAllRole(RoleID),
        PermisionLevel = tms.PermisionLevels.ToList(),
        TechnologyType = tms.TechnologyTypes.ToList(),
        serverPermisionLevel = tms.SecurityroleTypePermisions
         .Where(a=>a.SecurityRoleID == RoleID)
         .Where(a2=>a2.TechnologyType.Name.ToLower() == "server")
         .SingleOrDefault().PermisionLevelID,
        rackPermisionLevel = tms.SecurityroleTypePermisions
         .Where(a => a.SecurityRoleID == RoleID)
         .Where(a2 => a2.TechnologyType.Name.ToLower() == "rack")
         .SingleOrDefault().PermisionLevelID,
        virtualMachinePermisionLevel = tms.SecurityroleTypePermisions
         .Where(a=>a.SecurityRoleID == RoleID)
         .Where(a2=>a2.TechnologyType.Name.ToLower() == "virtual machine")
         .SingleOrDefault().PermisionLevelID,
        routerPermisionLevel = tms.SecurityroleTypePermisions
         .Where(a=>a.SecurityRoleID == RoleID)
         .Where(a2=>a2.TechnologyType.Name.ToLower() == "router")
         .SingleOrDefault().PermisionLevelID,
        switchPermisionLevel = tms.SecurityroleTypePermisions
         .Where(a => a.SecurityRoleID == RoleID)
         .Where(a2 => a2.TechnologyType.Name.ToLower() == "switch")
         .SingleOrDefault().PermisionLevelID
    };
    return c;
}
catfood
  • 4,267
  • 5
  • 29
  • 55
  • 2
    What line gives you the NRE? – Erik Philips Jul 18 '13 at 22:24
  • 3
    Unchecked use of `SingleOrDefault` can give you a null reference exception if no value was found. `Single` would throw an exception that there was no matching element in the collection, but `SingleOrDefault` will just return `null`, at which point you're currently trying to reference a property on a `null` object. In other words, it's probably not the property you're *setting*, but rather the expression from which you set it. – David Jul 18 '13 at 22:26
  • 4
    Literally every line of that snippet could throw a null reference exception. Adding nullable fields to your `SecurityRoleGroupAssign` in no way guards against the construction of an instance of the class from having errors. – Preston Guillot Jul 18 '13 at 22:27
  • 1
    Welcome to Stack Overflow! 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 Jul 18 '13 at 22:41

2 Answers2

2

The problem is that SingleOrDefault will return null (for reference types) if no items exist. So any time you call .SingleOrDefault().PermisionLevelID you're in danger of a null reference exception. you can fix this by placing the .SingleOrDefault() after the selected the result—e.g.(... select p.PermissionLevelID).SingleOrDefault().

Try this:

var permissions = tms.SecurityroleTypePermisions.Where(a => a.SecurityRoleID == RoleID);
SecurityRoleGroupAssign c = new SecurityRoleGroupAssign
{
    SecurityRole = FindAllRole(RoleID),
    PermisionLevel = tms.PermisionLevels.ToList(),
    TechnologyType = tms.TechnologyTypes.ToList(),
    serverPermisionLevel = 
        (from p in permissions
         where p.TechnologyType.Name.ToLower() == "server"
         select p.PermisionLevelID)
        .SingleOrDefault(),
    rackPermisionLevel = 
        (from p in permissions
         where p.TechnologyType.Name.ToLower() == "rack"
         select p.PermisionLevelID)
        .SingleOrDefault(),
    virtualMachinePermisionLevel = 
        (from p in permissions
         where p.TechnologyType.Name.ToLower() == "virtual" 
         select p.PermisionLevelID)
        .SingleOrDefault(),
    routerPermisionLevel = 
        (from p in permissions
         where p.TechnologyType.Name.ToLower() == "router")
         select p.PermisionLevelID
        .SingleOrDefault(),
    switchPermisionLevel =
        (from p in permissions
         where p.TechnologyType.Name.ToLower() == "switch"
         select p.PermisionLevelID
        .SingleOrDefault()
};

Or better yet:

var permissions = tms.SecurityroleTypePermisions
                     .Where(a => a.SecurityRoleID == RoleID)
                     .ToLookup(a => a.TechnologyType.Name.ToLower(),
                               a => a.PermisionLevelID);
SecurityRoleGroupAssign c = new SecurityRoleGroupAssign
{
    SecurityRole = FindAllRole(RoleID),
    PermisionLevel = tms.PermisionLevels.ToList(),
    TechnologyType = tms.TechnologyTypes.ToList(),
    serverPermisionLevel = permissions["server"].SingleOrDefault(),
    rackPermisionLevel = permissions["rack"].SingleOrDefault(),
    virtualMachinePermisionLevel = permissions["virtual"].SingleOrDefault(),
    routerPermisionLevel = permissions["router"].SingleOrDefault(),
    switchPermisionLevel = permissions["switch"].SingleOrDefault()
};
p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
1

.SingleOrDefault():

Returns the only element of a sequence, or a default value if the sequence is empty; this method throws an exception if there is more than one element in the sequence.

serverPermisionLevel = tms.SecurityroleTypePermisions.Where(a=>a.SecurityRoleID == RoleID).Where(a2=>a2.TechnologyType.Name.ToLower() == "server").SingleOrDefault().PermisionLevelID;

The problem here is that the .SingleOrDefault(); call returned the default "null" value. The error is thrown when you try to call the PermissionLevelID on that null reference.

What you could change it into:

 serverPermisionLevel = tms.SecurityroleTypePermisions
.Where(a=>a.SecurityRoleID == RoleID)
.Where(a2=>a2.TechnologyType.Name.ToLower() == "server")
.Select(r => r.PermissionLevelID).SingleOrDefault();

this way, your nullable ints will be filled when .SingleOrDefault actually returns null, or with the actual value of the PermissionLevelId if there is one.

Thousand
  • 6,562
  • 3
  • 38
  • 46