ASP.NET MVC / C# : how to remove a record id from url?

Viewed 421

How can I remove the ID from the url in this situation below where I am loading records from my database in which each record has an ID and a SEO slug name of the record. I have searched for this dozens of times but never seem to quite get a working answer.

mypictures.com/animal/cat-pictures/1
mypictures.com/animal/dog-pictures/2
mypictures.com/animal/bird-pictures/3

In this example I have a website that has different categories of animals. Each one of these exists in the database. The Cat category has Animal_Id = 1, the dog category has Animal_Id = 2 , Bird Category Animal_Id = 3 and so on.

I want to only show the slug of that category BUT NEVER THE ID. I am using SEO friendly urls so the answer would have to take that into account. I know that one way to maybe do it is to have unique slugs for each record but still I don't even know where to begin.

Below is what my code looks like so far that makes this work with the horrible id in the url:

AnimalController:

public ActionResult Details(int? id)
{
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }

        tblAnimal tblAnimal = db.tblAnimals.Find(id);            

        if (tblAnimal == null)
        {
            return HttpNotFound();
        }
                  
        return PartialView("_animalProdListPageLoad", tblAnimal);         
}

This is the cshtml view that calls the partial view _animalProdListPageLoad that loads a list of animal picture accessories once we have landed on the Animal category page. This uses the id that I am trying not to pass in the url. I added this part to the explanation to illustrate that I still need the id to load stuff that connects to the tblAnimalPictures via the Animal_Id. In this case AnimalAccessories is connected to the Animal_Id table, so I would still need the ID I just don't want it in the url if that makes sense.

@model mypictures.Models.tblAnimal

@{ Html.RenderAction("GetAnimalAccesories", "Animal", new { Animal_Id = Model.Animal_Id });
                                        
                                        @Html.HiddenFor(Model => Model.Animal_Id)

                                        ViewBag.Store_Id_Passed = Model.Animal_Id;
                                    }

Then in my RouteConfig I have the following to show the SEO friendly routes:

routes.Add("AnimalDetails", 
               new SeoFriendlyRoute2("animal/{slug}/{id}",
               new RouteValueDictionary(new { controller = "Animal", action = "Details" }),
               new MvcRouteHandler()));

Then I have a class that handles that SeoFriendlyRoute2 that looks like this:

public class SeoFriendlyRoute2 : System.Web.Routing.Route
{
    public SeoFriendlyRoute2(string url, RouteValueDictionary defaults, IRouteHandler routeHandler) : base(url, defaults, routeHandler)
    {
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var routeData = base.GetRouteData(httpContext);

        if (routeData != null)
        {
            if (routeData.Values.ContainsKey("id"))
                routeData.Values["id"] = GetIdValue(routeData.Values["id"]);
        }

        return routeData;
    }

    private object GetIdValue(object id)
    {
        if (id != null)
        {
            string idValue = id.ToString();

            var regex = new Regex(@"^(?<id>\d+).*$");
            var match = regex.Match(idValue);

            if (match.Success)
            {
                return match.Groups["id"].Value;
            }
        }

        return id;
    }
    
    private object GetslugValue(object slug)
    {
        if (slug != null)
        {
            string slugValue = slug.ToString();

            var regex = new Regex(@"^(?<id>\d+).*$");
            var match = regex.Match(slugValue);

            if (match.Success)
            {
                return match.Groups["id"].Value;
            }
        }

        return slug;
    }
}

Then in the tblAnimal model I have this, which is what generates the seo url slug:

public string GenerateSlug2()
    {            

        string phrase2 = string.Format("{0}-{1}", Animal_Id, slug);                        

        string str2 = RemoveAccent2(phrase2).ToLower();
        // invalid chars           
        str2 = Regex.Replace(str2, @"[^a-z0-9\s-]", "");
        // convert multiple spaces into one space   
        str2 = Regex.Replace(str2, @"\s+", " ").Trim();
        // cut and trim 
        str2 = str2.Substring(0, str2.Length <= 45 ? str2.Length : 45).Trim();
        str2 = Regex.Replace(str2, @"\s", "-"); // hyphens   
        return str2;
    }

    private string RemoveAccent2(string text)
    {
        byte[] bytes = System.Text.Encoding.GetEncoding("Cyrillic").GetBytes(text);
        return System.Text.Encoding.ASCII.GetString(bytes);
    }

Then finally when run the application and navigate to the animal category for any of the records like Dog it looks like this:

mypictures.com/animal/dog-pictures/2

but I REALLY need this instead:

mypictures.com/animal/dog-pictures

Please Help Me, I have been stuck on this for months and really need a solution.

I have already tried this and just get a 404: I removed the id from the route config since I thought that was a possible solution but its not.

routes.Add("AnimalDetails", new SeoFriendlyRoute2("animal/{slug}",
   new RouteValueDictionary(new { controller = "Animal", action = "Details" }),
    new MvcRouteHandler()));
1 Answers

edit your route config like this

routes.Add("AnimalDetails", new SeoFriendlyRoute2("animal/{slug}",
       new RouteValueDictionary(new { controller = "Animal", action = "Details" }),
        new MvcRouteHandler()));
Related