Register   Login
     
  Latest Posts  
Front Page Layout
by bmurphy on 8/29/2008 10:20 PM
RE: Tagging
by FBCO on 8/29/2008 8:20 PM
RE: Redesigning Elements of News Articles
by SteveJ on 8/29/2008 7:33 PM
RE: Redesigning Elements of News Articles
by makkabokka on 8/29/2008 7:20 PM
RE: Redesigning Elements of News Articles
by pspeth on 8/29/2008 5:51 PM
RE: Redesigning Elements of News Articles
by smcculloch on 8/29/2008 3:42 PM
RE: Sorry you have to be logged in
by smcculloch on 8/29/2008 3:40 PM
Sorry you have to be logged in
by albertramsbottom on 8/29/2008 3:37 PM
RE: Maximum photo upload
by marshal on 8/29/2008 2:08 PM
RE: Maximum photo upload
by smcculloch on 8/29/2008 2:04 PM
  Forums  
Subject: A Version of FriendlyUrls with multiple parameter handling and 301 redirects
Prev Next
You are not authorized to post a reply.

Page 1 of 212 > >>
Author Messages
bchapmanUser is Offline
Registered Users
Nuke Super Newbie
Nuke Super Newbie
Posts:21

8/30/2007 6:37 PM  

Taking up the challenge from the FriendlyUrl project page, I did further modifications to Scott's code, to incorporate the following requirements I had:

- Do something friendly with mutiple parameter pages (ie mypage/key1/value1/key2/value2).  I re-arranged the query parameters to have the tab path, then the query parameters, then the first of the query parameter keys as the pagename.  Ie mypage/value1/key2/value2/key1.aspx  Depending on the 'name' of the key1 value, this can result in a meaningful Url.

-Implement a 301 redirect for 'non friendly' url requests, so that Google and other bots should update their indexes from 'old' urls (such as default.aspx?tabid=38 and /tabid/38/default.aspx) to the new urls (either mypage.aspx or mypage/value1/key1.aspx)

I have a blog entry on it on my blog at http://www.ifinity.com.au/Blog/TechnicalBlog/tabid/60/EntryID/19/Default.aspx  The source code is available for download from http://www.ifinity.com.au/Whatwedo/FreeDownloads/tabid/388/Default.aspx

(that site does not yet have the code installed, hence the unfriendly Url)

To see the friendly Urls in action, it's been implemented on a new Auctioneer Listing site I've been working on: www.auctionlink.com.au  The use of the parameter re-arranging can be seen in the tag cloud and Auctioneers directory listings.

If you are going to try the code out, please test it as it I have only concentrated efforts on how it interacts with the site I designed it for.  I am interested in any other people's input though.

-Bruce


iFinity DotNetNuke Modules
Scott McCullochUser is Offline
Administrators
Nuke Master
Nuke Master
Posts:11396


8/31/2007 8:26 AM  
Thanks Bruce, I'll take a look at what you have done. I'm going to be spending a bit of time over the weekend on this project.

Scott McCulloch
Site Administrator
bchapmanUser is Offline
Registered Users
Nuke Super Newbie
Nuke Super Newbie
Posts:21

8/31/2007 10:06 PM  

You'll probably find with a compare I did some rearranging, but most of the code is 'new' - in that I tried to leave the existing code the same in terms of logic.

The appearance changes are more me getting my head around the way it worked.  And also getting used to VB again :-)


iFinity DotNetNuke Modules
green flashUser is Offline
Gold Membership
Nuke Wiz
Nuke Wiz
Posts:118

9/01/2007 12:59 AM  
Great work Bruce, any chance to let us use your Tags module?

DotNetNuke Turkish Community
y01nkUser is Offline
Registered Users
Nuke Master
Nuke Master
Posts:201


9/01/2007 5:52 AM  
Posted By brucerchapman on 8/30/2007 6:37 PM
...

-Implement a 301 redirect for 'non friendly' url requests, so that Google and other bots should update their indexes from 'old' urls (such as default.aspx?tabid=38 and /tabid/38/default.aspx) to the new urls (either mypage.aspx or mypage/value1/key1.aspx)

...



oooh- dreamy!
This is particularly important for late-comers like myself, as Google is already very familiar with the site structure based on the prior urls. Provided that the 301 is the proper method for preciseley this situation, I think this is a tremenous addition- thanks!


generated by sloganizer.net
bchapmanUser is Offline
Registered Users
Nuke Super Newbie
Nuke Super Newbie
Posts:21

9/01/2007 5:52 AM  
@greenflash

The Tags module will be available as a module, but I won't be giving it away for free. I'm not sure on pricing just yet. It's not quite ready yet, I want to make sure it works flawlessly with some of the more common modules before releasing it.

iFinity DotNetNuke Modules
bchapmanUser is Offline
Registered Users
Nuke Super Newbie
Nuke Super Newbie
Posts:21

9/01/2007 6:00 AM  
Just another point:

My blog page has eaten the web.config settings. They shoudl be (and I hope the forum page doesn't eat it as well!)

add name="DNNFriendlyUrl" type="DotNetNuke.Services.Url.FriendlyUrl.DNNFriendlyUrlProvider,
DotNetNuke.HttpModules.UrlRewrite" includePageName="true" regexMatch="[^a-zA-Z0-9 _-]" urlFormat="HumanFriendly" redirectUnfriendly="true" doNotRedirect="SearchResults;"

iFinity DotNetNuke Modules
Déclic VidéoUser is Offline
Gold Membership
Nuke Master
Nuke Master
Posts:564


9/09/2007 1:47 PM  

Hello,

I am also very interested in this version of Friendly URls.
Before putting it onto my website, I would like to know if it is compatible with the maxhyphenate module of Take1 ???
I would like to keep the possibility of having hyphenate...

Original discussion is there:
http://www.ventrian.com/Support/ProductForums/tabid/118/forumid/35/postid/20748/view/topic/Default.aspx

Thanks so much,
DV FX


Non linear video editing software, tips and tricks, tutorials... Déclic Vidéo FX
RabidmaxUser is Offline
Registered Users
Nuke Active Member
Nuke Active Member
Posts:34

9/09/2007 9:07 PM  
Hiya DV,

I just had a look at the blog that Bruce put in his first post, and from what I read there it looks like it should be fully compatible with my hyphenating module.

Bruce, just to make sure: Your changes are just to this friendly url dll, nothing in the dnn core, and it uses the tab path from the database as it used to in the original/unmodified version? If that's the case, the hyphenate module will work fine, as the module does it's thing outside of the realm of the friendly url provider, just changing the tab path records in the database. As Dax pointed out in the other thread, my module would be useful in SEO even for dnn sites without Scotts friendly url provider.

Hope that clears things up a bit :)
Max
bchapmanUser is Offline
Registered Users
Nuke Super Newbie
Nuke Super Newbie
Posts:21

9/09/2007 10:21 PM  
Bruce, just to make sure: Your changes are just to this friendly url dll, nothing in the dnn core, and it uses the tab path from the database as it used to in the original/unmodified version? If that's the case, the hyphenate module will work fine, as the module does it's thing outside of the realm of the friendly url provider, just changing the tab path records in the database. As Dax pointed out in the other thread, my module would be useful in SEO even for dnn sites without Scotts friendly url provider.

Hope that clears things up a bit :)
Max


Hi Max

Yes, the changes I have made are just to the internals of the HttpUrlRewrite module, no other core changes.  It does use the tab path to configure the url.  The changes I made are to Scott's posted version, and all I did was reconfigure the code a bit in terms of layout, and then add in a new section to handle url's that have parameters in them (ie view/post/forumid/35 etc

The way it works with single pages (ie mysite/mypage/tabid/11/default.aspx) is to reformat, the same way Scott's module does - mysite/mypage.aspx.  Then for pages with parameters, it puts the page name, and adds a path of value1/key2/value2/key1.aspx.  The only reformatting of parameters is the switching around of their order-  if they have a hyphen in them, it stays that way.    However currently there is a bug in my version where it doesn't recognise hyphens or apostrophes correctly - I've got a fix but haven't bundled a release of it just yet.

A lot of people get a bit bamboozled by the Url rewriting because it seems a bit akin to witchcraft in terms of fiddling with the incoming address of something.  But the base DotNetNuke code relies of changing the incoming urls around, there's nothing too difficult about it.  You just need a good rosetta stone piece of code, so that you can translate the base url (which, at the core, is default.aspx?tabid=nn&kkey1=value1 etc...) into something friendly - and then - when that friendly comes back in you can re-translate it back to what the framework expects.   Mostly this is done with regular expressions - so it just comes down to how complex you can write your regular expresssions.

I'll post on this thread when I release a new version of my code.

-Bruce


iFinity DotNetNuke Modules
RabidmaxUser is Offline
Registered Users
Nuke Active Member
Nuke Active Member
Posts:34

9/09/2007 11:11 PM  

Thanks Bruce, that's pretty much what I got from your blog entry too, so my hyphenate module should work fine with your changes.

The only thing I can see that could be a problem is 'which tabpath?'... By this I mean if I had a url of /home/support/products/shopping/stuff.aspx, will your code translate correctly through to the page with the tabpath of \\home\\support\\products\\shopping\\stuff, rather than /home.aspx?stuff=support&products=shopping, and that kind of thing? What happens when the page that should be really displayed is the latter, will we ever know? Does the code assume that the longest match is the correct one, meaning you can't use the key-in-path substitution on non-'leaf' tab path nodes?

That's about all I'd be concerned about I think.

I noticed you were wanting ideally to be able to drop the .aspx from your urls, /home/shopping.aspx would be nice as /home/shopping, or /home/shopping/... As far as I'm aware the .aspx is pretty necessary, unless you have access to an ISAPI rewrite dll, in the IIS settings. If so, I put some thoughts down here (near the bottom): http://www.ventrian.com/Support/ProductForums/tabid/118/forumid/35/postid/20748/view/topic/tpage/2/Default.aspx

but came up with the same stuff (but better) here: http://www.ventrian.com/Support/ProductForums/tabid/118/forumid/35/postid/21420/view/topic/Default.aspx  (see the PS at the bottom of the first post, it includes the post from the link above...)

If you would like to have a click around on this website: http://library.tauranga.govt.nz/ it demonstrates a few things I am quite pleased with (I was 'functionality guy', not 'make it pretty man', so no comments on the overall look :P). It has scotts friendly url running on it, uses the code from the link above for the child portal alias handling (http://library.tauranga.govt.nz/localhistory/ for example), uses the .aspx behind the scenes code (http://library.tauranga.govt.nz/localhistory/historic-photographs), and uses the MaxHyphenate module (v2.0 I think) which does the hyphens for the tab paths, lowercases, and is a scheduled task, running every few minutes. We were pretty happy with the way the URLs came out, and so were the comms department (.aspx is so ugly on a bus!).

Anyway, hope I didn't wander too far off topic there!

Cheers,
Max :)

Scott McCullochUser is Offline
Administrators
Nuke Master
Nuke Master
Posts:11396


9/09/2007 11:47 PM  
That looks great Max, you post some interesting points about the tabPath and the parameters getting confused. (Part of the reason I never tackled it in the first release).

To remove the aspx you need to map all requests through the aspnet worker processor, this would allow you to have an extension free environment (or even an alternate extension, e.g. .php)

When I spoke to Shaun, I identified a few problem areas:-

1.) www.domain.com/products/gallery.aspx (portal is www.domain.com and tabpath is products/gallery) - Works OK

2.) www.domain.com/child/products/gallery.aspx (is the portal www.domain.com or www.domain.com/child?)
-------> Solution, put a delimiter in for child portals? www.domain.com/child/pages/products/gallery.aspx

3.) www.domain.com/products/gallery/param1/value.aspx (the portal is www.domain.com, but what is the tabpath and what are the parameters?)
-------> Solution, put a delimiter in or move the parameters, www.domain.com/products/gallery/~/param1/value or www.domain.com/products/gallery.aspx/param1/value

The big problem with delimiters is that they make the url non-hackable. I'd be interesting to know what you think (so we can moved forward).

Bruce, do you have any concerns in integrating this into 1 project? (maybe via a central repository?)

Scott McCulloch
Site Administrator
bchapmanUser is Offline
Registered Users
Nuke Super Newbie
Nuke Super Newbie
Posts:21

9/10/2007 1:05 AM  
@Max

The way I work the tab path is the same as in Scott's original. The pages are iteratively examined until one with the tabpath is found - only after that do you start working with parameters. That way the parameters are never confused with the tab path. Theoretically I guess you could have a tab path that was the same as a parameter path, but to me it's a useful compromise. So, in your example, /home/support/products/shopping/stuff.aspx would be looking for a tabpath matching home/support/products/shopping/stuff- if one was found then processing would continue. So you can have as many parameters as you like, but with the caveat that none of the parameter paths should match any tab path - not difficult to avoid but it can happen. The solution is different page naming.

I know this isn't the best way to do it (iteratively checking all tabs for a tabpath match). If I were writing it from scratch, I'd put the tabs into a dictionary using a tabpath key, and use the .ContainsKey() function to check if my tab matched. However no such animal exists and I didn't want to start writing db scripts that had to be installed along with the provider.

@scott

No concerns at all - integrate away if you like!

As for removing the .aspx extension - it's true that you have to map a wildcard through IIS so that all processes get forwarded. This might be difficult for people with shared hosting, but I don't think that's a reason not to, as long as it's a configurable (say, via web.config). The internet is headed back to it's roots, with REST formats gaining in popularity over SOAP complexity, and Search engines driving the charge back towards simple and easy to read Url's.

Your examples are tough to decipher, and I admit I didn't give much though to child portals and the like in my developments. But given that child portals and child aliases are in the database, I guess it can be dealt with in the same way as tab paths - worst case you could iterate each child portal and each tab path combination to find a match on porta/tabpath - then sort out the /param/value based on what's left over. The tab paths and child portal names are already known so can be identified in the incoming path. What, then, is needed is an efficient and fast way of matching all possible combinatiions of childportal/tabpath. For simple sites, it's not a problem, but I've no idea what the upper limit of the union of child portals and tabs are in other people's DNN installations.

Perhaps a hash of the key of the child portal name + tab path could be made, and then a dictionary of tab id's (unique across portals, remember) could be cached using that the key. The reason I say a hash is that you should be able to generate a different value for child/path than just path, even if the text values are the same. Thus the incoming child portal and tab path are iteratively extracted in a series of ever more complex regex expressions, checked for existience in the dictionary, and then the relevant tabid returned when one is found. I believe an approach like this would cover all of your three scenarios.

1.) www.domain.com/products/gallery.aspx -> key would be : '' + 'products/gallery'
2.) www.domain.com/child/products/gallery -> key would be : 'child/' + 'products/gallery'
3.) www.domain.com/products/gallery/param1/value.aspx -> key would be '' + 'products/gallery'

In the case of 1 and 3 the code woudl return a unique result. In the 2nd case a unique tab would be returned, as it has the child portal in it. The regex to start with would be something like (and this is pseudo-regex!): (/[.]+).aspx). If the results from that got no match, then you could go with (/[.]+)(//[.]+) and so on, until you found your match.

so the pseudocode would be something like
{at app startup}
//build tab dictionary
foreach (tab in portal.tabs)
addToDictionary(tab)

foreach (childPortal in portal.childPortals)
foreach (tab in childPortal.tabs)
addtoDictionary(tab)

{on incoming request}
//recursively check for regex match
do until found
regexString = regexString + another page path level
match = regex.match(regexString, incomingUrl)
if match
if tabDictionary.containskey(match.value)
return tabid
if not match
regexString = regexString + anotherLevel


I'm not sure if this approach would even be faster than iterating all tabs and child portal tabs, I'd have to play with it and see. Perhaps a special dictionary could be set up to keep only the top N most popular childportal/tabpath combos, and this would be looked up in the first instance. In most sites there are goign to be 5 or so pages that far outrank all the others in terms of pageviews.

I guess the point I'm trying to make is that I see it as a solveable problem - it's just the performance that needs to be optimised.

Perhaps in retrospect it's all a bit too much 'thinking out loud'. I'll mull over it a bit more and see how I get on.

BTW I have also developed a data-driven unit testing project for testing lots of different combinations of input Urls if you're interested. It needs Visual Studio Team Suite with the Unit Testing add on to run, but it helps with checking if you've made a breaking change. Only small problem is that I have found a bug in the HttpContext mocking, and the original author (Phil Haack) hasn't yet got back to me. It only causes minor problems. Anyway let me know if might be useful if you want to take this up a notch.

iFinity DotNetNuke Modules
RabidmaxUser is Offline
Registered Users
Nuke Active Member
Nuke Active Member
Posts:34

9/10/2007 3:44 AM  
I really like your psuedo code there Bruce. The only thing I'd change is on your incoming URLs, you'd need a regex more like (pseudo, haven't regexed in a couple of months): (/[.]+)((/[^/]+/[^/]+)*?).aspx

The reason I've done it like this is that each parameter will need to be a pair, so the last set of brackets ($2?) will take a /key/value pair off at a time (I think). Then I added the *? at the end, so that each successive match will be with another pair removed (the non greedy thing). I think. This would then match the entire path to .aspx into $1 the first time, then knock off a pair at the end for the next attempt (assuming that the tabDictionary.containskey failed to find anything). It should be a decent speed since I'd guess most/a lot of pages will be parameter-free.

For a url:
www.domain.com/child/product/support/shop/stuff.aspx
pass 1: Check /child/product/support/shop/stuff (no match in dictionary)
pass 2: Check /child/product/support (no match)
pass 3: Check /child (match, parameters are ?product=support&shop=stuff, or however you want to arrange them)

I also think that your psuedo code there would be a good way to deal with scotts child problem. I agree it's not ideal, I could still make a child portal called /homewrecker/ and a page called /homewrecker/ too (I think?), which might cause issues. But unless you go the whole delimiter way or some such, I don't see a better way.

Either way, it won't matter overly. I could make two pages, say we title one 'Gasp' and the other 'Gasp....', and both would boil down to Gasp.aspx.

Oooh boy, think that might put a kink into your tabDictionary come to think of it... Having them both with the same key would throw an error when you try to build it up. I suppose the same thing with the portal /child and a page of /child... Maybe that's why it hasn't been done yet.

I like the 'thinking out loud' conversations, keep it up, it's interesting! I like watching thought processes like such.

Cheers :)
bchapmanUser is Offline
Registered Users
Nuke Super Newbie
Nuke Super Newbie
Posts:21

9/10/2007 5:13 AM  
Posted By Take1 on 9/10/2007 3:44 AM

I also think that your psuedo code there would be a good way to deal with scotts child problem. I agree it's not ideal, I could still make a child portal called /homewrecker/ and a page called /homewrecker/ too (I think?), which might cause issues. But unless you go the whole delimiter way or some such, I don't see a better way.

Either way, it won't matter overly. I could make two pages, say we title one 'Gasp' and the other 'Gasp....', and both would boil down to Gasp.aspx.

Oooh boy, think that might put a kink into your tabDictionary come to think of it... Having them both with the same key would throw an error when you try to build it up. I suppose the same thing with the portal /child and a page of /child... Maybe that's why it hasn't been done yet.


The problem of having a child portal and tab name  matching a parent portal and tab path (ie mydomain.com/child/page.aspx (child is the parent tab name) and mydomain.com/child/page.aspx (child is the portal)) - that's why I think I'd try and hash up the key somehow.  Because you would be assembling the key yourself, you can put something in it to differentiate between a child portal/tab path and plain old tab path.  When it came to trying to find the tab, first you'd try a regex with the path as a tab path, then you'd try it as a child portal/tab path.  Because you are only expecting two different scenarios, then it's not much of an overhead to try.  Of course, the problem comes with large amounts of child portals - I suppose there are hosting companies running dotnetnuke out there who have large numbers of child portals and performance could die considerable.  Then again perhaps a one-size-fits-all solution leaves too many compromises and what is needed is different optimisation options.  Ie better performance, uglier urls/slower performance, better urls.  In my case I'll take the better urls every time and throw hardware, caching and optimisation at the problem.

Same goes for the gasp and gasp...   You could work on some type of value that differentiated the two while still allowing both to be deciphered from the url.  Worst case is stick a int value or something back into the url gasp and gasp_2.   I do this in my directory module running on auctionlink.com.au.  When I get two auctioneers with the same name (happens when you have franchised companies) I just assign each with an incrementing integer.  It's not the prettiest but it works for the rare case where it's needed.  If you don't like it then rename it with a unique name. We are all used to having to come up with unique usernames for user accounts, it's not that much of a leap.

Either that, or you could just throw an exception which said 'don't name two pages the same, dummy'.  Most people test their pages, if not, their visitors will soon tell them it's not working.    As I mentioned before (I think) - these sorts of things don't have to be completely idiot-proof, it just has to handle the vast majority of cases, and degrade nicely where it doesn't work for the rest.  I think that's pretty easily done.  You could put the exception in the http urlrewrite module and it woudl still bubble up OK.


iFinity DotNetNuke Modules
Déclic VidéoUser is Offline
Gold Membership
Nuke Master
Nuke Master
Posts:564


9/10/2007 12:41 PM  
Well, I am a bit lost with your technical discussion. Nevertheless, please inform us whenever you have a fully working version with hyphenate, I would be more than happy to try it.

DV FX

Non linear video editing software, tips and tricks, tutorials... Déclic Vidéo FX
Dax DavisUser is Offline
Gold Membership
Nuke Master
Nuke Master
Posts:227


9/10/2007 5:20 PM  

Man, this is a great thread (I admit it's a bit over my head as well).  Don't forget SSL!!!  :)  Thanks for all the work, this sounds like a great solution.

 

Dax

bchapmanUser is Offline
Registered Users
Nuke Super Newbie
Nuke Super Newbie
Posts:21

9/13/2007 6:22 PM  
Just an update, I've got a new version working pretty well in testing. This has the following features:

- dictionary based lookup of tabs instead of iterating all tabs (basically following the logic I laid out in a previous post)
- support for hyphens in the url's
- child portal urls to be parentportal/childportal/page
- bugs fixed from my first release (which included inability to logout, bad url resolving when odd numbers 'child' pages were used, errors in url's with hyphens and a few other things)

I've also got it working so that the .aspx extension can be dropped. This requires modification of the IIS settings so won't be any good for shared hosts, but I've made it configurable via web.config.

I'll post the links to the updated version on this thread when I release it next week sometime.

-Bruce

iFinity DotNetNuke Modules
Scott McCullochUser is Offline
Administrators
Nuke Master
Nuke Master
Posts:11396


9/13/2007 6:35 PM  
Thanks Bruce - those are some of the changes I was going to make (dictionary based lookup)

Did you add the extension as an attribute of the provider?

When you say parentportal/childportal/page, is what follows that the tabpath?

Can we sync up development? (central source control?) I was going to spend a fair bit of time over the weekend on this.

Scott McCulloch
Site Administrator
bchapmanUser is Offline
Registered Users
Nuke Super Newbie
Nuke Super Newbie
Posts:21

9/14/2007 12:30 AM  
Scott,

Yes, I put the extension in as an attribute for the FriendlyUrlProvider, although the UrlRewrite uses it as well. I've also put in an option of when to use the extension - always, page only and never. Always and never are obviuos, page only is for when there is no parameter values. I've also put in an attribute for how to treat parameters - the options are 'ordered' and 'firstlast'. Ordered is parm1key/parm1value/parm2key/parm2value. Firstlast is like I had in my first version, with parm1value/parm2key/parm2value/parm1key. Obviuosly by dropping the .aspx extension you can make a much nicer path, so with my taglist I can get www.auctionlink.com.au/auctioneer/tags/tag/motor+vehicles/ - which conforms to the published tag miniformat - what I was after.

So, being as specific as I can, parentportal/childportal/page - page would be the tabpath. if you had a subpage, then it would be parentportal/childportal/page/subpage - and it would either end in / or .aspx, depending on your confirguation. Of course, the 301 redirect code also works to fix up if you leave off the end /, or put on the .aspx. So long as I can get it fast and reliable it should be 'the last word' in url rewriting! A fair bit of testing is needed though, as one things for sure, with the number of modules and DNN installs out there, people sure have some crazy urls.

I've got a bit more tidying up to do in terms of the source code - I'm more than happy to synch it in a central source control. I'm open to suggestion on how you want to do this - were you thinking codeplex or something??

iFinity DotNetNuke Modules
You are not authorized to post a reply.
Page 1 of 212 > >>

Forums > Projects > Friendly Urls > A Version of FriendlyUrls with multiple parameter handling and 301 redirects



ActiveForums 3.7