简体   繁体   中英

ASP.NET MVC - Routing works for /home but not for /home/index

I am trying to add views for a project I completed online.

When I load the default web-page, my Index action in the Home controller loads up. When I navigate to /home, my Index action in the Home controller loads up. However, when I navigate to /home/index, an error pops up.

This is my default route in my startup class:

app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller}/{action}/{id?}",
                    defaults: new { controller = "Home", action = "Index" });
            })

And this is my Index method in my home controller:

public class HomeController : Controller
    {
        private readonly IMovieRankService _movieRankService;

        public HomeController(IMovieRankService movieRankService)
        {
            _movieRankService = movieRankService;
        }

        [HttpGet]
        public async Task<ActionResult> Index()
        {
            var other = await _movieRankService.GetAllItemsFromDatabase();
            return View(other);
        }

My index view:

@using Movie_Rank.Contracts;
@model IEnumerable<MovieResponse>

@{
    ViewData["Title"] = "movies";
}

<h2>movies</h2>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.MovieName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Description)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Ranking)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.TimeRanked)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.MovieName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Description)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Ranking)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.TimeRanked)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
                @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
                @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
            </td>
        </tr>
}
    </tbody>
</table>

When I run the program, my table of movies loads up fine. When I put /home into the url, my table of movies loads up fine. But when I put in /home/index, it gives this error:

    NullReferenceException: Object reference not set to an instance of an object.
MovieRank.Libs.Mappers.Mapper.ToMovieContract(MovieDb movie) in Mapper.cs
-
        18. }
        19.
        20. public MovieResponse ToMovieContract(MovieDb movie)
        21. {
        22.     // Returns new MovieResponse which maps proprties of MovieDb (using DynamoDB table attributes
        23.     // For example, MovieName (from MovieResponse class) = movie.MovieName (from MovieDb)
      **24.**   return new MovieResponse
        25.     {
        26.         MovieName = movie.MovieName,
        27.         Description = movie.Description,
        28.         Actors = movie.Actors,
        29.         Ranking = movie.Ranking,
        30.         TimeRanked = movie.RankedDateTime
MovieRank.Services.MovieRankService.GetMovie(int userId, string movieName) in MovieRankService.cs
-
        31. 
        32. // Get a movie from MovieDb in MovieRankRepository and map to MovieResponse
        33. public async Task<MovieResponse> GetMovie(int userId, string movieName)
        34. {
        35.     var response = await _movieRankRepository.GetMovie(userId, movieName);
        36.     // Uses MovieRankRepository response
      **37.**   return _map.ToMovieContract(response);
        38. }
        39.
        40. // Get movies from MovieDb in MovieRankRepository and map to MovieResponse
        41. public async Task<IEnumerable<MovieResponse>> GetUsersRankedMoviesByMovieTitle(int userId, string movieName)
        42. {
        43.     var response = await _movieRankRepository.GetUsersRankedMoviesByMovieTitle(userId, movieName);
MovieRank.Controllers.HomeController.GetMovie(int userId, string movieName) in HomeController.cs
-
        25. }
        26. 
        27. [HttpGet]
        28. [Route("{userId}/{movieName}")]
        29. public async Task<ActionResult> GetMovie(int userId, string movieName)
        30. {
      **31.**   var result = await _movieRankService.GetMovie(userId, movieName);
        32. 
        33.     return View(result);
        34. }
        35. 
        36. [HttpGet]
        37. [Route("user/{userId}/rankedMovies/{movieName}")]

So we know that when you use /Home/Index , it's using this action:

public async Task<ActionResult> GetMovie(int userId, string movieName)

That has to do with the route you gave it:

[Route("{userId}/{movieName}")]

Because the route, at this point, doesn't know the type that userId should be, it's matching userId = "Home" and movieName = "Index" . Then when the values are mapped, the value types don't match, and I assume you're probably getting 0 for userId in the method itself.

Try adding a constraint in the route, to make sure the route is only selected if userId is an int :

[Route("{userId:int}/{movieName}")]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM