Attempted to read or write protected memory

2019-06-07 06:54发布

问题:

I have a sample ASP.NET MVC 3 web application that is following Jonathan McCracken's Test-Drive Asp.NET MVC (great book , by the way) and I have stumbled upon a problem. Note that I'm using MVCContrib, Rhino and NUnit.

    [Test]
    public void ShouldSetLoggedInUserToViewBag() {
        var todoController = new TodoController();
        var builder = new TestControllerBuilder();
        builder.InitializeController(todoController);

        builder.HttpContext.User = new GenericPrincipal(new GenericIdentity("John Doe"), null);

        Assert.That(todoController.Index().AssertViewRendered().ViewData["UserName"], Is.EqualTo("John Doe"));
    }

The code above always throws this error:

System.AccessViolationException : Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

The controller action code is the following:

[HttpGet]
    public ActionResult Index() {
        ViewData.Model = Todo.ThingsToBeDone;
        ViewBag.UserName = HttpContext.User.Identity.Name;

        return View();
    }

From what I have figured out, the app seems to crash because of the two assignements in the controller action. However, I cannot see how there are wrong!?

Can anyone help me pinpoint the solution to this problem.

Thank you.

Edit 1

I've done some experiments to see what the problem is. When removing the ViewData,Model assignment the problem transcends in Expected result to be of type ViewResult. It is actually of type ViewResult.. The ViewData assignment is so basic that I do not think that it is the problem so I think there is something wrong with either Rhino or MVCcontrib in conjunction with MVC 3.

I also have the following test written earlier for the same controller action:

        [Test]
    public void ShouldDisplayAListOfTodoItems() {
        Assert.That(((ViewResult)new TodoController().Index()).ViewData.Model, Is.EqualTo(Todo.ThingsToBeDone));
    }

This one fails now with System.NullReferenceException : Object reference not set to an instance of an object probably becuase there's no HttpContext set up for this particular test. When removing the ViewBag assignment, everything is ok.

Hope that makes the problem more clear.

Edit 2

When debugging the code after removing the ViewData.Model assignment, it throws a different error: System.NullReferenceException : Object reference not set to an instance of an object. on the ViewBag assignment.

回答1:

Well, I've knocked this one down. As I have suspected, it was because of MVCContrib. Mind that I am using MVC 3 Beta which is not yet officially supported by MVCContrib. With that in mind, I have downloaded the latest MVCContrib sources for MVC 3 branch.

Go to MVCContrib Sources, switch to the mvc3 branch, download, and build the binaries with the attached bat. Then, include the needed files into your solution.

Well, this will probably get fixed in a future stable release, but I guess it might be useful to others. Thank you Darin for your interest.



回答2:

How about this:

[Test]
public void ShouldSetLoggedInUserToViewBag() 
{
    // arrange
    var todoController = new TodoController();
    var builder = new TestControllerBuilder();
    builder.InitializeController(todoController);

    builder.HttpContext
        .Stub(x => x.User)
        .Return(new GenericPrincipal(new GenericIdentity("John Doe"), null));

    // act
    var actual = todoController.Index();

    // assert
    actual.AssertViewRendered();
    Assert.That(todoController.ViewData["UserName"], Is.EqualTo("John Doe"));
}

and the controller action:

[HttpGet]
public ActionResult Index() 
{
    ViewBag.UserName = HttpContext.User.Identity.Name;
    return View(Todo.ThingsToBeDone);
}

Remark: I would include the information into the view model and avoid using ViewData/ViewBag. It is not strongly typed and it forces you to use magic quotes.