URL Routing in Sitefinity 5.0
Hello Sitefinity Team,
Thanks for all the good work you've done so far with sitefinity.
We developed couple of new custom modules for our wesite, and now it'is time to find a solution for seo friendly urls. URL Routing comes to mind right away since it's very easy to do it in asp.net 4.0 framework. However after trying the standard asp.net 4.0 way for routing we realized that Sitefinity uses its own route handlers to serve the pages. After the reasearch we found few posts on these forums with workarounds. Please see the code below that we were able to put together using those samples:
public
class
DCOCustomRoute : SitefinityRoute
public
override
System.Web.Routing.RouteData GetRouteData(HttpContextBase httpContext)
//get the path from the httpContext variable and parse it
var virtuallPath =
this
.GetVirtualPathInternal(httpContext);
//where directory/categories is the name of the Virtual page in sitefinity
if
(virtuallPath.Contains(
"directory/categories"
))
//parse the acutal path to find the PageSiteNode from the sitemap provider
var sitemapProvider =
this
.GetSiteMapProvider();
if
(sitemapProvider ==
null
)
return
null
;
bool
isAdditional;
string
[] pars;
//where /directory/categories is the Virtual Path in SiteFinity
var node = sitemapProvider.FindSiteMapNode(
"/directory/categories"
,
false
,
out
isAdditional,
out
pars);
if
(node !=
null
)
return
this
.GetRouteDataInternal(pars, httpContext.Request.QueryString, node);
return
base
.GetRouteData(httpContext);
public
static
void
RegisterType()
ObjectFactory.Container.RegisterType<SitefinityRoute, DCOCustomRoute>();
protected
override
SiteMapBase GetSiteMapProvider()
var siteMapProvider =
base
.GetSiteMapProvider();
SystemManager.CurrentHttpContext.Items[SiteMapBase.ProviderKey] = siteMapProvider;
return
siteMapProvider;
protected void Application_Start(object sender, EventArgs e)
Telerik.Sitefinity.Services.SystemManager.ApplicationStart += new EventHandler<
EventArgs
>(SystemManager_ApplicationStart);
void SystemManager_ApplicationStart(object sender, EventArgs e)
DCOCustomRoute.RegisterType();
RouteTable.Routes.Insert(1, new DCOCustomRoute());
var node = sitemapProvider.FindSiteMapNode("/categories", false, out isAdditional, out pars);
var node = sitemapProvider.FindSiteMapNode("/categories", false, out isAdditional, out pars);
to:
var node = sitemapProvider.FindSiteMapNode("/directory/categories", false, out isAdditional, out pars);
And unfortunately it's not working properly when destination page is a child of the root page. the destination page http://www.oursite/directory/categories is NOT editable anymore in sitefinity administration.
It only works/editable when the destination page is a root page.
It is important for as to have the destination page as a child page since we would like to display it in navigation menu under the root in the following format:
root: Business Directory (url http://www.oursite/directory/)
child one: By Category (url http://www.oursite/directory/categories)
child two: By Location (http://www.oursite/directory/locations)
As I sad the following pages should be able to receive the following urls
http://www.oursite/directory/categories should receive http://www.oursite/directory/categories/fishing
and
http://www.oursite/directory/locations should receive http://www.oursite/directory/locations/stateNameHere
We will appreciate any help here from your team or sitefinity community.
And last but not least. If possible I would like to ask sitefinity team to add new feature request in issue tracker for us to vote for making URL Routing much simplier/flexible in sitefinity.
Thanks.
Actually, it is pretty easy to use the Sitefinity routing. If you create a control and add it to a page, you can capture the params and check you data. If your data has a value, you can set a flag to load the page, or you can let the control finish loading and the site will throw a 404.
using
Telerik.Sitefinity.Web;
public
class
YourClass : SimpleView
protected
override
CreateChildControls()
base
.CreateChildControls();
CheckForFilter();
protected
void
CheckForFilter()
// Get the parameters sent to the page
var parms = (
string
[])
this
.Page.Request.RequestContext.RouteData.Values[
"Params"
];
if
(parms !=
null
)
//Check the params against your data here
foreach
(
string
param
in
parms)
// If data match call below help
// This is still listed as dperecated, but I have not heard of the new helper
// This will tell sitefinity that this page is were we need to be
// If this is not called, then you will more than likely get a 404
RouteHelper.SetUrlParametersResolved(
true
);
for
(
int
i = 0; i < parms.Length; i++)
switch
(
params
[i])
// check for key
case
"fishing"
:
i++;
// Get Value
valueVariable = parms[i];
break
;
// check for key
case
"state"
:
i++;
// Get Value
valueVariable = parms[i];
break
;
Hello Richard,
Thanks for the explanations.
Looks that in your example you are showing how to access the parameters in a Routed Page
Can you show me how you register routes in sitefinity?
For example in asp 4.0 I will do it in global.asax in the following way:
void Application_Start()
RegisterRoutes(RouteTable.Routes);
void RegisterRoutes(RouteCollection routes)
routes.MapRoute(
"directory-category", //Name of the Route (can be anything)
"directory/categories/category", // URL with parameters
"~/directory/category.aspx"); //Page which will handles and process the request
This route will forward the following url http://www.mysite.com/directory/categories/fishing to ~/directory/category.aspx page
And here how I can access URL parameters in a Routed Page
string categoryName = Page.RouteData.Values["category"].ToString();
Well that is the nice thing about the Sitefinity routing. Since you would have already created the page ~/directory/categories, Sitefinity will already know that you want to load that page. The routing is already handled by Sitefinity in the SitefinityRoute class. That is why I said it is actually easy to use.
You might refer back to this page also. Further down, Radoslav responds to someone who is trying to use routing in which the page is part of the Sitefinity sitemap. Radoslav's example is for blogs, but you could use the same logic for querying your data. In this example, they are calling GetUrlParameterString. This is a method from and extension class in Sitefinity. It is basically just calling the Page.Request.RequestContext.RouteData.Values["Params"] but instead of getting an array of the params, it builds a concatenated string separated by a forward slash.
Thanks for your help Richard.
It works.
Great comments and input on this feature; it's helped me a lot. Have you done this before - or considered - modifying the keywords of the page - per dynamic URL? So /directory/categories/fishing/bass would have keywords in the page related to fishing and bass; where as directory/categories/fishing/trout would have different keywords related to trout. This concept can carry forward for the page title, etc....
Any ideas or examples?
Hi,
I tried using the code on my page on which I have to get the values from URL
var parms = (string[])this.Page.Request.RequestContext.RouteData.Values["Params"];
if (parms != null)
foreach (string param in parms)
RouteHelper.SetUrlParametersResolved(true);
It works fine if the parameter does not have any special characters in it. Say "Self-Study & TextBox" or "Seld-Study CD/ w Textbox"
Is there any way to recognize these values on the page.
The url will be urlencoded Self & Study will be Self+%26+Study
You can unencode the string before you do your logic.
Thanks for replying.
When I encode the word "Self & Study" it gives me an error "A potentially dangerous Request.Path value was detected from the client
(&). " I have attached the screenshot of the error.
What am I doing wrong?
I think the problem is that you are trying to use this as a file path and thus the error. It is best not to use special characters in your actual page url. If you want to use them as querystrings, then you can url encode them.
Thanks to Richard we've got the answer to URL routing a while ago.
To create our parameters we decided to replace special characters and save it in the database.
Here some sample that can be used to format the parameters before saving in DB.
public static string FormatRoutingParameter(string param)
string charsToRemove = @" ~`!@#$%^*()-=+\|[];:',<>/";
param = ReplaceCharsInBag(param.Trim(), ".", "");
param = ReplaceCharsInBag(param.Trim(), "&", "and");
return ReplaceCharsInBag(param, charsToRemove, "_");
// Replaces all characters from string s which appear in string bag with new character
public static string ReplaceCharsInBag(string s, string bag, string newChar)
int i;
// Search through string bag characters one by one.
for (i = 0; i < bag.Length; i++)
// Get current character from the bag.
string c = bag.Substring(i, 1);
s = s.Replace(c, newChar);
return s;