How can I get pretty urls like localhost:8888/News/Example-post instead of localhost:8888/Home/Details/2
My HomeController has the following for the Details method
public ActionResult Details(int id)
{
var ArticleToView = (from m in _db.ArticleSet where m.storyId == id select m).First();
return View(ArticleToView);
As the ASP.NET routing system is somewhat complicated, there are many ways to accomplish what you describe.
First of all, do you just want to have a pretty URL for the Details method? If so, you might consider renaming HomeController to NewsController or moving the Details method into a new NewsController class - that will automatically form the /News
part of the URL. If you don't want a /Details
part, you might rename your Details method Index
, as that will be automatically called by /News
. Finally, you need to change your int id
parameter into string name
.
If you want many custom URLs, you're going to have to define your own routes. Here are two ways of doing this:
1.
The easiest way I've found is to use an ASP.NET MVC Attribute-Based Route Mapper. That way, all you have to do is add an attribute on each method you want a pretty URL for and specify what URL you want.
First, you must follow a few steps to set up the attribute-based route mapping system, as outlined on that link.
After completing those steps, you must change your method to look like this:
[Url("News/{name}")]
public ActionResult Details(string name)
{
var ArticleToView = (from m in _db.ArticleSet where m.storyName == name select m).First();
return View(ArticleToView);
}
2.
Alternatively, you can define your custom routes manually in Global.asax.cs
. In your RegisterRoutes
method, you can add the following in the middle:
routes.MapRoute(
"NewsDetails",
"News/{name}",
new { controller = "News", action = "Details", name = "" }
);
What I do on my sites is that I check the URL against either the Page Title or Page Stub in cases where the page titles could have the same name for instance if you have a site that posts a "Picture of the Week" you may want to use a stub instead of title as you'll have multiples named the same thing.
URLs look like this: http://mySite.com/Page/Verse-of-the-Week
Global.asax contains this:
routes.MapRoute("Pages", "{controller}/{pageID}", new { controller = "Page", action = "Index", pageID = "Home" });
PageController is this:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Index(string pageID)
{
if (pageID == null)
{
pageID = pageRepository.HomeOrLowest();
}
var p = pageRepository.ByStub(pageID);
if (p == null) { return RedirectToAction("NotFound", "Error"); }
return View(p);
}
The repository looks like this:
private static Func<mvCmsContext, string, Page> _byStub =
CompiledQuery.Compile((mvCmsContext context, string pageTitle) =>
(from p in context.Pages
where p.pageTitle.Replace(" ", "-") == pageTitle
select p).SingleOrDefault());
public Page ByStub(string pageTitle)
{
return _byStub(context, pageTitle);
}
I hope that helps.
Edit to add duplicate handling:
private static Func<mvCmsContext, string, int> _pageExists =
CompiledQuery.Compile((mvCmsContext context, string pageTitle) =>
(from p in context.Pages
where p.pageTitle.Replace(" ", "-") == pageTitle
select p).Count());
public bool PageExists(string pageTitle)
{
return Convert.ToBoolean(_pageExists(context, pageTitle));
}
Validates like this:
IValidationErrors errors = new ValidationErrors();
if (CreateOrEdit == "Create")
{
if (pageRepository.PageExists(model.pageTitle) && !String.IsNullOrEmpty(model.pageTitle))
errors.Add("pageTitle", "A page with this title already exists. Please edit it and try again.");
}
Please check out this package I've created: https://www.nuget.org/packages/LowercaseDashedRoute/
And read the one-line configuration here: https://github.com/AtaS/lowercase-dashed-route