G Gr
G Gr

Reputation: 6080

display url slug instead of id in mvc

I have a blogging application and users are able to create posts, I used Entity framework to create the model from the database. In Posts I have an entry for UrlSlug.

However when I check the details of a post:

Controller:

    public ActionResult Details(int id = 0)
    {
        Post post = db.Posts.Find(id);
        if (post == null)
        {
            return HttpNotFound();
        }
        return View(post);
    }

It returns a url with id at the end: http://localhost:52202/Post/Details/1

I have tried returning post.UrlSlug (throws an error) aswell as changing my RouteConfig.cs file to use urlslug instead of id (which does display the urlslug, but it cant find the page because of the controller). How can I change this so urlslug is displayed instead of the Post Table Id?

RouteConfig.cs

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

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

View:

@for (int i = 0; i < Model.Count(); i += 3)
{
    <div class="row">
        @foreach (var item in Model.Skip(i).Take(3))
        {
            <div class="col-md-4 portfolio-item">
                <a href="@Url.Action("Details", "Post", new { id = item.Id })">
                    <img class="img-responsive" src="http://placehold.it/700x400" alt="">
                </a>
                <h3>
                    <a href="@Url.Action("Details", "Post", new { id = item.Id })">@Html.DisplayFor(modelItem => item.Title)</a>
                </h3>

                <p>@Html.DisplayFor(modelItem => item.ShortDescription)</p>

            </div>
        }

    </div>
}

@Html.PagedListPager(Model, page => Url.Action("Index", new { page, pageSize = Model.PageSize }))

Edit

An issue I noticed is on this line:

    public ActionResult Details(string urlslug)
    {
        Post post = db.Posts.Find(urlslug); //find only finds an eitity with a given primary key, how can I change this to find the string urlslug

Upvotes: 3

Views: 3817

Answers (3)

Saeed Khan
Saeed Khan

Reputation: 3

An issue I noticed on the below line:

public ActionResult Details(string urlslug)
{
    Post post = db.Posts.Find(urlslug); //find only finds an eitity with a given primary key, how can I change this to find the string urlslug

You can select data with the help of urlslug by using Where instead of Find

i.e. Post post = db.Posts.Where(x=> x.urlslug == urlslug).FirstOrDefault();

Upvotes: 0

CodeCaster
CodeCaster

Reputation: 151594

An action method does not dictate the URL, it only matches a request. You need to print the slug:

@Url.Action("Details", "Post", new { slug = item.Slug })

Then add to the routing to support the URL structure you want:

routes.MapRoute(
    name: "PostWithSlug",
    url: "Post/Details/{slug}",
    defaults: new {  }

And alter the action method:

public ActionResult Details(string slug)
{
}

But besides that, you do want an ID in the URL. Otherwise you can't use the same post title twice.

Upvotes: 5

Jacob Roberts
Jacob Roberts

Reputation: 1815

You can either rename your argument in your controller to match the 'slug' name. So instead of

public ActionResult Details(int id = 0)

Use

public ActionResult Details(int urlslug = 0)

Alternative is to remove id from your route config like

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

Keep in mind, what ever you argument name is in your Action, that name is used as the GET variable in your url. So if the argument is int id, then your url must be like ?id=1.

Upvotes: 0

Related Questions