1

I am developing a website which contains some tutorials using MVC4 and entity framework. All the tutorials will be saved in database and based on the Tutorial Id (say TId) provided in the requested URL it will retrieve all the information regarding that tutorial in the action method and render in the view and display to the user. A sample URL is mentioned below.

URL: www.mysite.com/Tutorials/Show/452

Where Tutorials is Controller Name and Show is the action method name.

Here 452 is the TId. So when this URL is requested tutorial with TId 452 will be displayed. But what I want is, I want to append the dashed tutorial name at the end as shown below.

www.mysite.com/Tutorials/Show/452/My-Test-Tutorial

I can replace the space with '-' and generate the string but I dint find a way to append it to the URL.

This works perfectly with stackoverflow site. For example, even though we request "In MVC4, how to redirect to a view from a controller action with parameters in the Url?" the question with Id "20035665" is getting displayed and URL will be changed to "In MVC4, how to redirect to a view from a controller action with parameters in the Url?".

Can anyone pls help me on this?

Community
  • 1
  • 1
Pranay
  • 442
  • 6
  • 14
  • `Tutorials` is the name of the controller, right? –  Aug 08 '14 at 07:15
  • Can I ask why you want to append name in URL which makes url lengthy? With Tid, server will know tutorial name anyway. Second even if you have strong reason to pass tutorial name, there are other ways to send data to server. – SBirthare Aug 08 '14 at 07:56
  • @Stefan Baiu.. Yes. Tutorials is the controller name and Show is the action method name. – Pranay Aug 08 '14 at 08:22
  • @SBirthare.. Am not including title in the url for passing input data to server but to make the url look friendly. Just by having a look at the URL we should be able to know the title. – Pranay Aug 08 '14 at 08:29
  • @kewlcoder: This also improves SEO, I'm using the method I have mentioned in my answer in my sites. – Saranga Aug 08 '14 at 09:23

2 Answers2

3

Assuming I understood your problem correctly, here's the solution I propose:

Add the following change to your routing mechanism:

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

        routes.MapRoute(
            name: "Tutorials",
            url: "Tutorials/{id}/{title}",
            defaults: new { controller = "Tutorials", action = "Show", title = UrlParameter.Optional },
            constraints: new { id = @"\d+" }
        );

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

and then in your Tutorials controller:

public class TutorialsController : Controller
{
    // GET: /Tutorials

    public ActionResult Index()
    {
        // here you can display a list of the most recent tutorials or whatever
        return View();
    }

    // GET: /Tutorials/1 (will be redirected to the one below)
    // GET: /Tutorials/1/Intro-into-ASP_NET-MVC

    public ActionResult Show(int id, string title)
    {
        string key = string.Format("tutorial-{0}", id.ToString());
        Tutorial model = TempData[key] as Tutorial;

        // if this is not a redirect
        if ( model == null )
        {
            model = GetTutorial(id);
        }

        // sanitize title parameter
        string urlParam = model.Title.Replace(' ', '-');
        // apparently IIS assumes that you are requesting a resource if your url contains '.'
        urlParam = urlParam.Replace('.', '_');
        // encode special characters like '\', '/', '>', '<', '&', etc.
        urlParam = Url.Encode(urlParam);

        // this handles the case when title is null or simply wrong
        if ( !urlParam.Equals(title) )
        {
            TempData[key] = model;
            return RedirectToAction("Show", new { id = id, title = urlParam });
        }

        return View(model);
    }

    private Tutorial GetTutorial(int id)
    {
        // grab actual data from your database
        Tutorial tutorial = new Tutorial { Id = 1, Title = "Intro into ASP.NET MVC" };
        return tutorial;
    }
}

UPDATE:

the solution presented above will redirect
/Tutorials/1
to
/Tutorials/1/Intro-into-ASP_NET-MVC.

If you actually want to display the action name in the url, like /Tutorials/Show/1/Intro-into-ASP_NET-MVC you can just change the "url" in the "Tutorials" route to url: "Tutorials/Show/{id}/{title}".

You can also replace the RedirectToAction with RedirectToRoute("Default", new { id = id, title = urlParam }); which will make sure it matches the route named "Default", but this approach would yield the following url: www.mysite.com/Tutorials/Show/1?title=Intro-into-ASP_NET-MVC

1

You can have a route config as below and when you create URLs you can pass tutorial title to a method which convert the given text to URL friendly text.

Example

In Route Config

routes.MapRoute(
    name: "Tutorials",
    url: "{controller}/{action}/{tid}/{title}",
    defaults: new { controller = "Tutorials", action = "Show", tid = UrlParameter.Optional, title = UrlParameter.Optional }
);

In a View when you create URLs

<a href='@Url.Action("Tutorials", "Show", new { tid = tutorial.ID, title = ToFriendlyUrl(tutorial.Title) })'>My Tutorial</a>

Then in Show method

public ActionResult Show(int tid, string title)
{
    // if the title is missing you can do a redirect inside action method

    return View();
}
Community
  • 1
  • 1
Saranga
  • 3,178
  • 1
  • 18
  • 26