This project is read-only.

Fixing Link Problems for Subcategories

Topics: Business Logic Layer
Sep 20, 2008 at 2:21 PM

Since 1.4.5 and nested categories, if you had a category list on your blog, subcategories were incorrectly linked. Say, you had a master category Foo and a subcategory for it named Egg, then the category link pointed to /category/foo-egg.aspx. Your server, however reported a "page not found" .NET exception.

The problem were in UrlRewrite.cs (BlogEngine.Core\Web\HttpModules\): The RewriteCategory method converts /category/ links to links based on "default.aspx?id=", using the category's title to find out the id. However, while category list links use the complete title (master category title concatenated with subcategory title), the method checked for category by using the single title property that does not include the master. So, taking the example further, the method were to look for a "foo-egg" category, however the Egg subcategory's title is only Egg.
The solution is rather simple, you only have to ask the method to use the complete (or concatenated) title for comparison.

The 5th line of the method reads:
string legalTitle = Utils.RemoveIllegalCharacters(cat.Title).ToLowerInvariant();

You have to change this to:
string legalTitle = Utils.RemoveIllegalCharacters(cat.CompleteTitle()).ToLowerInvariant();

And things will work fine. I didn' noticed any problem with RSS feed linking, so there's no need to tickle with those. After the modification, build your BlogEngine.Core project and copy BlogEngine.Core.dll from your bin directory to your blog's Bin directory.

Sep 20, 2008 at 8:26 PM
Worked perfectly. Thanks!
Sep 22, 2008 at 2:45 AM
here is another fix that i used... same issue but i just attacked it from the where the invalid url is being created.  You will still have to recompile and copy over the app_code.dll file.

I kind of like the idea of the link being the full title instead of the just that category's title.  Thats the main difference between my code change it will leave your category's link that points to just the name/title of the category and the above fix will leave the full title as the url. 

I also know that when the postview is generated and displays the categories in the footer that my method still works i'm not 100% sure on the above fix. I think that the class pageviewbase would also need to be changed the way its generates the links.  the code for that is in the method postviewbase.categorylinks().  which leads me to think that the above fix is not 100% with out the change to the PostViewBase code, but even then its still an easy fix.


Sep 22, 2008 at 7:23 AM
Hi Joey,

Thanks for the alternative solution. My question is how can you handle the cases when there are two categories with the same name belonging to other master categories. Say you have two master cats VB and C# (to stick to IT, once we are taling about coding :]) and for both you want to create a subcat called samples and code conventions. Isn't these hit each other?

I guess this is only a theoretic question, 'cuse I just can't tell you in the morning (what is here now), before completing my coffee :) whether the engine allows for categories with the same name (is the GUID generated from full title or not?), and anyway, such a situation may indicate that you should create four categories and use VB+samples, C#+samples and other combos to properly cat'ize your posts.

(And thanks for the thanks for Taylex)

Sep 22, 2008 at 12:12 PM
Edited Sep 22, 2008 at 12:14 PM
yad is correct about the generated categories in the footer and also about the easy fix. Open PostViewBase.cs make the changes below, recompile and upload the BlogEngine.Core.dll

string category = Category.GetCategory(Post.Categories[i].Id).Title; 


string category = Category.GetCategory(Post.Categories[i].Id).CompleteTitle();

Sep 22, 2008 at 12:46 PM
Edited Sep 22, 2008 at 12:47 PM
good point e-m.  My Solution would not allow samples in both the VB and C# categories.  I didnt even consider that when i made the fix.  The solution to use the full title is most likly the better of the two, i'm just not 100% sure that those two changes are the only ones needed.  i will do a search on category.title.  like you ssaid... its early but it would make sense to me if all category.title where changed over to the complete/full title.  no?
Sep 22, 2008 at 12:59 PM
Hi Yad,

Personally I'd prefer an option that allows me to choose whether I want to display full title or not. Just compare the following two layout and decide which one suits better for given purposes:

  • VB
    • Data Access
    • Code conventions
  • C#
    • Data Access
    • Code conventions
-- or --

  • VB
  • VB - Data Access
  • VB - Code conventions
  • C#
  • C# - Data Access
  • C# - Code conventions
I guess the first one suits better in the most cases.

Yeah, you can do a search for category.title. As I recognized, the point of interest is in the rewriter when the engine transforms /category/ links. Here it uses the category name to construct the GUID. This would not allow for similarly named categories. Maybe the guys should change this way of identification so that the engine uses the full title to generate the GUID. 

Another idea is to use /category/mastercategory/subcategory links. This would also require the change in GUID generation to allow for similary named cats, however the links were more friendly for the eye and the rewriter should be prepared for checking the presence of a master category in a link.

Jan 19, 2009 at 1:24 AM
Ah, excellent.  Two places to make a change to get this corrected, thank you all.  I found one more place you might want to make this change.  In the admin, when you are adding a post or editing one, the category list doesn't display the cats in the same way.  So, to be thorough, here's the admin page to update and the code to change.

admin\pages\add_entry.aspx.cs ~ line 276

Change this:
cblCategories.Items.Add(new ListItem(Server.HtmlEncode(cat.Title), cat.Id.ToString()));

To this:
cblCategories.Items.Add(new ListItem(Server.HtmlEncode(cat.CompleteTitle()), cat.Id.ToString()));