MVC Routing News Pages

135 views Asked by At

I have managed to get my MVC project to present a list of news items in an SEO friendly manner:

/News/ - to present the list

/News/NewsItem/id/news-item-title - the individual news item

What I would really like is:

News/id/news-item-title

Exactly how Stackoverflow presents its questions.

However, I cant seem to get my head around how to do the routing to differentiate between two actions with the same controller action name (Index).

Any suggestions would be appreciated.

EDIT:

Here's my routes config:

routes.MapRoute(
    "News",
    "News/NewsItem/{newsId}/{newsTitle}",
    new { controller = "News", action = "NewsItem", newsTitle = UrlParameter.Optional },
    new { newsId = @"\d+" }
);

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

EDIT 2:

This is what I've amended everything to:

Route

routes.MapRoute(
    "News",
    "{controller}/{id}/{newsTitle}",
    new { action = "NewsItem", newsTitle = UrlParameter.Optional }
);

Controller

public class NewsController : Controller
{
     public ActionResult Index()
     {
         var q = _ctx.tblNews.OrderBy(x => x.newsCreateDate)
                  .Where(x => x.WebsiteID == 2).ToList();
         return View(q);
     }

     public ActionResult NewsItem(int newsId, string newsTitle)
     {
          return View();
     }
}

View - Index (Segment)

<table>
    @foreach (var x in Model)
    {
        <tr>
            <td>@Html.ActionLink(x.newsTitle, "NewsItem", new { newsId = x.newsID, newsTitle = x.newsTitle.ToSeoUrl() })
            </td>
        </tr>
    }
</table>

Actionlink produces: News/NewsItem?newsId=3&newsTitle=my-news-item

I want: News/3/my-news-item

1

There are 1 answers

4
TSmith On BEST ANSWER

One way you could do this is to introduce an additional route into the route configuration

RouteConfig.cs:

            routes.MapRoute(
            name: "News_seo_friendly",
            url: "{controller}/{id}/{seo}",
            defaults: new { action = "NewsItem", seo = UrlParameter.Optional }
        );

*Note the action value in this route. You will need a corresponding action method on that controller. Also, since this route is more specific it goes above the existing, more generic route(s)

An Alt RouteConfig.cs that might be safer:

            routes.MapRoute(
            name: "News_seo_friendly",
            url: "News/{id}/{seo}",
            defaults: new { controller = "News", action = "NewsItem", seo = UrlParameter.Optional }
        );

NewsController:

    public ActionResult NewsItem(string id)
    {
        return View();
    }

Another way you could do this is to make "News" its own Area within the project. This gives you the opportunity to isolate your routes, if your app is larger, and flexibility for your controller name(s).

Edited after feedback Wanted to draw attention to the fact that the parameter name on the controller's NewsItem() method should match what is being declared in the route settings. In the above scenario, url: "{controller}/{id}/{seo}"
should match the parameter name in NewsItem(string id)...or vice-versa.