Object reference not set to an instance of an object. - Roles doesn't exist on application startup

StackOverflow https://stackoverflow.com/questions/19041031

  •  29-06-2022
  •  | 
  •  

So, I've got an MVC4 application, and I'm using the default login and registration system. On the home page, I want to redirect or change a message based on a user's role. Here's what I've got in the controller:

    public ActionResult Index()
    {
        if (Roles.GetRolesForUser().Contains("Admin"))
            ViewBag.Message = "Click on a link to get started.";
        else if (Roles.GetRolesForUser().Contains("Authorized"))
            ViewBag.Message = "Click on Organizations or Interfaces to get started.";
        else if (Roles.GetRolesForUser().Contains("Unauthorized"))
            ViewBag.Message = "An administrator must activate your account before you can use this tool.";
        else
            return RedirectToAction("Login", "Account");
        return View();
    }

Normally, this works just fine, but if I restart the application while I'm logged in, and after making code changes, then I get the error "Object reference not set to an instance of an object." And it's pointing at Roles, which apparently doesn't exist yet.

After way too much searching, I found somebody with the same problem. I tried the suggested solution there, and replaced all instances of Roles.GetRolesForUser().Contains with HttpContext.User.IsInRole, but then I got this error: "A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)"

After a bunch more searching I found this, which pointed me here, which says that neither of my attempts will work because I need a redirect first. Although, he's apparently talking about something else, but it looks pretty similar.

I tried having Index redirect to Index2, which redirected to Index3, containing the same code, and I got the same error. I tried clickable links to get from Index to Index2 to Index3, same error. I tried forcing a logoff by putting WebSecurity.Logout(); right before the line of code that causes the error, and I get a different error: "You must call the "WebSecurity.InitializeDatabaseConnection" method before you call any other method of the "WebSecurity" class. This call should be placed in an _AppStart.cshtml file in the root of your site." But the built-in logoff method doesn't appear to call that, it's got a different thing going:

    @using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm" })) {
        @Html.AntiForgeryToken()
        <a href="javascript:document.getElementById('logoutForm').submit()">Log off</a>
    }

which, when clicked, immediately calls WebSecurity.Logout();

So that's about the limit of what I know how to do. I guess I need a way to force a logoff whenever I start the application, and it's even ok if it's bound to the index page, because I can pretty much avoid the index page after logging on. Or if there were a way to get it to recognize the logged on user, that would be even better.

To get around it, at first I was commenting out all the problematic code, restarting it, clicking log off, then uncommenting and restarting. Then I figured out that deleting the cookie in my browser fixes it. I still don't want to have to do it every time. If I can't figure out a solution, I'm just going to force the user to click a log off link that takes them to the login page.

有帮助吗?

解决方案 2

Ok, finally got it figured out. Romoku's answer was helpful but I don't have enough reputation yet to vote it up :(

The try/catch block works, but it still hangs for a while while it tries to connect, and then it hits the HttpException block with the message "Unable to connect to SQL Server database." Then it routes over to the Login page, but what's weird to me is that on the login page, it's able to detect who is logged in, and even better, I have similar code in the _Layout.cshtml file [@if (Roles.GetRolesForUser().Contains("Admin"))] to filter menu options, and it runs those correctly on the login page. Which is really strange, because I had already tried redirecting to Index2 and Index3 before, with no luck. So I figured maybe I just have to redirect to a different controller, and I added a "Tester" controller, no dice.

Turns out the AccountController class has a [InitializeSimpleMembership] attribute above it, and all I have to do to make the original code work as intended is add that above the HomeController class, plus the "using MyProject.Filters;" statement.

Even funnier is that I had searched the solution for "WebSecurity.InitializeDatabaseConnection" whenever I got the corresponding error before, found the statement in "SimpleMembershipInitializer()" in the Filters folder, then searched the solution for "SimpleMembershipInitializer" and didn't find any other hits. Who knew it was hidden in the [InitializeSimpleMembership] attribute.

其他提示

the code can throw a NullReferenceException since you're not checking the result of Roles.GetRolesForUser.

Try:

string[] roles;

try
{
    roles = Roles.GetRolesForUser();
}
catch(HttpException)
{
    return RedirectToAction("Login", "Account");
}

if(roles == null) return RedirectToAction("Login", "Account");

if(roles.Contains("Admin")
{
    ViewBag.Message = "Click on a link to get started.";
}
else if (roles.Contains("Authorized"))
{
    ViewBag.Message = "Click on Organizations or Interfaces to get started.";
}
else if (roles.Contains("Unauthorized"))
{
    ViewBag.Message = "An administrator must activate your account before you can use this tool.";
}
else
{
    return RedirectToAction("Login", "Account");
}

return View();

If you use Roles.IsUserInRole then the code can be simplified to:

try
{
    if(Roles.IsUserInRole("Admin"))
    {
        ViewBag.Message = "Click on a link to get started.";
    }
    else if(Roles.IsUserInRole("Authorized"))
    {
        ViewBag.Message = "Click on Organizations or Interfaces to get started.";
    }
    else if (Roles.IsUserInRole("Unauthorized"))
    {
        ViewBag.Message = "An administrator must activate your account before you can use this tool.";
    }
    else
    {
        return RedirectToAction("Login", "Account");
    }
}
catch(ArgumentNullException)
{
    // No user is currently logged in
    return RedirectToAction("Login", "Account");
}
catch(HttpException)
{
    // There is no current logged on user. Role membership cannot be verified.
    return RedirectToAction("Login", "Account");
}

return View();
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top