WhiskerBiscuit
WhiskerBiscuit

Reputation: 5157

Why is RedirectToAction returning null?

I have the following class, where a user will access a controller AT/1/2 which means project 1, step 2. If the user enters a project and not a step (2nd method/route) it should use step 99. If the user fails to enter anything, it should use project 1, step 99. I can easily fix this by calling the overloaded method manually, but I thought I should be able to accomplish the same thing with RedirectToAction. However in the 2nd and 3rd methods, v is null in my unit tests.

My RegisterRoutes looks like:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapMvcAttributeRoutes(); //MVC 5 Attribute Routes

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

I'm not sure what I'm missing here.

public class ATController : Controller
{
    [AllowAnonymous]
    [Route("{project}/{step}")]
    public ActionResult Index(int project, int step)
    {
        var m = new ATViewModel();
        m.Project = project;
        m.Step = step;
        return View(m);
    }

    [AllowAnonymous]
    [Route("{project}")]
    public ActionResult Index(int project)
    {
        var v = RedirectToAction("Index", new { project, step = 99 });
        return v;
    }

    [AllowAnonymous]
    public ActionResult Index()
    {
        var v = RedirectToAction("Index", new { project = 1, step = 99 });
        return v;
    }
}

Upvotes: 2

Views: 528

Answers (1)

Nkosi
Nkosi

Reputation: 247098

Referencing Attribute Routing in ASP.NET MVC 5, there were some minor updates needed on your controller

[RoutePrefix("at")]
public class ATController : Controller
{
    //GET /at/1/2
    [AllowAnonymous]
    [Route("{project}/{step}")]
    public ActionResult Index(int project, int step)
    {
        var m = new ATViewModel();
        m.Project = project;
        m.Step = step;
        return View(m);
    }

    //GET /at/1
    [AllowAnonymous]
    [Route("{project}")]
    public ActionResult Index(int project)
    {
        var v = RedirectToAction("Index", new { project = project, step = 99 });
        return v;
    }

    //GET /at
    [AllowAnonymous]
    [Route("")]
    public ActionResult Index()
    {
        var v = RedirectToAction("Index", new { project = 1, step = 99 });
        return v;
    }
}

Here are also some unit tests for your controller that all pass (GREEN) when tested.

[TestClass]
public class MvcControllerAttributeRouteTests : ControllerUnitTests {
    [TestMethod]
    public void Index_Should_Return_ViewResult_With_Model() {
        //Arrange
        int project = 1;
        int step = 2;
        var controller = new ATController();
        //Act
        var actionResult = controller.Index(project, step);
        var viewResult = actionResult as ViewResult;
        //Assert
        Assert.IsNotNull(viewResult);
        Assert.IsNotNull(viewResult.Model);
        Assert.IsInstanceOfType(viewResult.Model, typeof(ATViewModel));
        var viewModel = viewResult.Model as ATViewModel;
        Assert.AreEqual(project, viewModel.Project);
        Assert.AreEqual(step, viewModel.Step);
    }

    [TestMethod]
    public void Project_Supplied_No_Step_Should_Redirect_To_Index() {
        //Arrange
        int project = 1;
        var controller = new ATController();
        //Act
        var actionResult = controller.Index(project);
        var result = actionResult as RedirectToRouteResult;
        //Assert
        Assert.IsNotNull(result);
        Assert.AreEqual("Index", result.RouteValues["action"], "the redirection was to at.index action");
        Assert.AreEqual(project, result.RouteValues["project"]);
    }

    [TestMethod]
    public void No_Porject_No_Step_Should_Redirect_To_Index() {
        //Arrange
        var controller = new ATController();
        //Act
        var actionResult = controller.Index();
        var result = actionResult as RedirectToRouteResult;
        //Assert
        Assert.IsNotNull(result);
        Assert.AreEqual("Index", result.RouteValues["action"], "the redirection was to at.index action");
        CollectionAssert.Contains(result.RouteValues.Keys, "project");
        CollectionAssert.Contains(result.RouteValues.Keys, "step");
    }
}

Upvotes: 1

Related Questions