3

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
G Gr
  • 6,030
  • 20
  • 91
  • 184
  • possible duplicate of [ASP.NET MVC: Routing custom slugs without affecting performance](http://stackoverflow.com/questions/11494184/asp-net-mvc-routing-custom-slugs-without-affecting-performance) – Sherif Ahmed Apr 20 '15 at 16:28
  • check this answer http://stackoverflow.com/a/11496379/2907017 – Sherif Ahmed Apr 20 '15 at 16:28

3 Answers3

5

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.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
0

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.

Jacob Roberts
  • 1,725
  • 3
  • 16
  • 24
  • Then change the type from int to string – Jacob Roberts Apr 20 '15 at 16:18
  • @GarrithGraham you tried what? Paste what you tried. – Jacob Roberts Apr 20 '15 at 16:22
  • The type of one of the primary key values did not match the type defined in the entity. See inner exception for details.\r\nParameter name: keyValues – G Gr Apr 20 '15 at 16:23
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/75737/discussion-between-jacob-roberts-and-garrith-graham). – Jacob Roberts Apr 20 '15 at 16:24
  • Agreed, I appreciate your help tho! On another note this is the inner exception The argument types 'Edm.Int32' and 'Edm.String' are incompatible for this operation. Near WHERE predicate, line 1, column 62."} – G Gr Apr 20 '15 at 16:26
  • Then your db context is requiring an int and you are passing a string. Change it back to int or change your db model to use string. – Jacob Roberts Apr 20 '15 at 16:30
0

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();

RamPrakash
  • 1,687
  • 3
  • 20
  • 25