I'm rewriting a website project with ASP.Net MVC 4 and I find it difficult to setup the right routes. The url structure is not RESTful or following a controller/action pattern - the pages have the following structure of slugs. All slugs are saved in the database.
/country
/country/carmake
/country/carmake/carmodel
/custom-landing-page-slug
/custom-landing-page-slug/subpage
Example:
/italy
/italy/ferrari
/italy/ferrari/360
/history-of-ferrari
/history-of-ferrari/enzo
Since Country
, Car Make
and Car Model
are different models/entities, I would like to have something like a CountriesController, CarMakesController and CarModelsController where I can handle the differing logic and render the appropriate views from. Furthermore, I have the custom landing pages which can have slugs containing one or more slashes.
My first attempt was to have a catch-all PagesController
which would look up the slug in the database and call the appropriate controller based on the page type (eg. CarMakesController
), which would then perform some logics and render the view. However, I never succeed to "call" the other controller and render the appropriate view - and it didn't feel right.
Can anyone point me in the right direction here? Thanks!
EDIT: To clarify: I do not want a redirect - I want to delegate the request to a different controller for handling logic and rendering a view, depending on the type of content (Country
, CarMake
etc.).
Since your links looks similar, you can't separate them at the routing level. But here are good news: you can write custom route handler and forget about typical ASP.NET MVC links' parsing.
First of all, let's append RouteHandler
to default routing:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Default", action = "Index", id = UrlParameter.Optional }
).RouteHandler = new SlugRouteHandler();
This allows you to operate with your URLs in different ways, e.g.:
public class SlugRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var url = requestContext.HttpContext.Request.Path.TrimStart('/');
if (!string.IsNullOrEmpty(url))
{
PageItem page = RedirectManager.GetPageByFriendlyUrl(url);
if (page != null)
{
FillRequest(page.ControllerName,
page.ActionName ?? "GetStatic",
page.ID.ToString(),
requestContext);
}
}
return base.GetHttpHandler(requestContext);
}
private static void FillRequest(string controller, string action, string id, RequestContext requestContext)
{
if (requestContext == null)
{
throw new ArgumentNullException("requestContext");
}
requestContext.RouteData.Values["controller"] = controller;
requestContext.RouteData.Values["action"] = action;
requestContext.RouteData.Values["id"] = id;
}
}
Some explanations are required here.
First of all, your handler should derive MvcRouteHandler
from System.Web.Mvc
.
PageItem
represents my DB-structure, which contains all the necessary information about slug:
ContentID
is a foreign key to contents table.
GetStatic
is default value for action, it was convenient in my case.
RedirectManager
is a static class which works with database:
public static class RedirectManager
{
public static PageItem GetPageByFriendlyUrl(string friendlyUrl)
{
PageItem page = null;
using (var cmd = new SqlCommand())
{
cmd.Connection = new SqlConnection(/*YourConnectionString*/);
cmd.CommandText = "select * from FriendlyUrl where FriendlyUrl = @FriendlyUrl";
cmd.Parameters.Add("@FriendlyUrl", SqlDbType.NVarChar).Value = friendlyUrl.TrimEnd('/');
cmd.Connection.Open();
using (var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
if (reader.Read())
{
page = new PageItem
{
ID = (int) reader["Id"],
ControllerName = (string) reader["ControllerName"],
ActionName = (string) reader["ActionName"],
FriendlyUrl = (string) reader["FriendlyUrl"],
};
}
}
return page;
}
}
}
Using this codebase, you can add all the restrictions, exceptions and strange behaviors.
It worked in my case. Hope this helps in yours.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With