views:

1202

answers:

3

I'd like to put together a forum/message board with ASP.NET MVC. Pretty common on these types of forums are hierarchical board categories, so for instance:

-General Discussion
-Technical Support
--Website Technical support
--Product Technical Support
---Product A Technical Support
---Product B Technical Support

Below each category are then topics and messages belong to those topics. What I'm primarily concerned with is 1.) getting to the correct place, given a URL, 2.) not including boatloads of unnecessary information in my URL, and 3.) being able to recreate a URL from code.

I'd like a URL to be something like this:

mysite.com/Forum/ - forum index
mysite.com/Forum/General-Discussion/ - board index of "general discussion" 
mysite.com/Forum/Technical-Support/Product/Product-A/ - board index of "Product A Tech Support"
mysite.com/Forum/Technical-Support/Website/Topic1004/ - Topic index of topic with ID 1004 in the "Website Technical Support" board
mysite.com/Forum/Technical-Support/Website/Topic1004/3 - Page 3 of Topic with ID 1004

Now, I've excluded Action names from this because they can be inferred based on where I am. Each Board entity in my database has a "UrlPart" column, which is indexed, so I expect to be able to do relatively fast queries against that table to figure out where I am.

The question is: in order to figure out the correct place, should I use a custom route handler, a custom route binder, or should I just create obscure routing rules?

This suggestion looks pretty good but it also looks like a lot of work for little benefit: http://stackoverflow.com/questions/379558/mvcnet-routing#379823

This seems to indicate that creating a model binding would be easier: http://stackoverflow.com/questions/296284/mvc-dynamic-routes

To fulfill #3 I'm going to have to create my own custom URL generation logic, right?

+5  A: 

If you need deep and/or non-conforming URLs, I would suggest that you employ attribute based routing, such as the solution discussed here.

I prefer an attribute based approach over putting every route in Application_Start, because you have better locality of reference, meaning the route specification and the controller which handles it is close together.

Here is how your controller actions would look for your example, using the UrlRoute framework I implemented (available on codeplex):

[UrlRoute(Path = "Forum")]
public ActionResult Index()
{
    ...
}

[UrlRoute(Path = "Forum/General-Discussion")]
public ActionResult GeneralDiscussion()
{
    ...
}

[UrlRoute(Path = "Forum/Technical-Support/Product/{productId}")]
public ActionResult ProductDetails(string productId)
{
    ...
}

[UrlRoute(Path = "Forum/Technical-Support/Website/{topicId}/{pageNum}")]
[UrlRouteParameterDefault(Name = "pageNum", Value = "1")]
public ActionResult SupportTopic(string topicId, int pageNum)
{
    ...
}

With this approach you can generate outbound URLs using the same helpers (Url.Route*, Url.Action*) that you would use if you manually added the routes using the default route handler, no extra work needed there.

DSO
Thanks DSO, but that's not quite what I was looking for; you can imagine people create forums with all manners of middle areas. All I need in a URL is the /Forum marker, to know to marshal to the Forum controller; and optionally, the topic ID and page number, to indicate whether I want to go to the index, a board, or a topic. I want the board names in there for SEO reasons. Arguably I could make only the current board be part of the URL, but chomping part of it off wouldn't obey the REST principal of getting to the parent section.
Rob
OK maybe I took your examples too literally. You're saying that you want the entire middle part of the URL be totally free-form with absolutely no predefined structure?
DSO
Yes. Part of it is that I'd like my URLs to get their structure from the database. This seems to be working... I'll post what I came up with a bit later today.
Rob
+1  A: 

You could have them all go to one controller action which handles the route handling for you by manually splitting the rest of the url out and calls what a method on your BLL which then delegates tasks to other methods finally returning a View() depending on your needs.

Schotime
+1  A: 

I've answered a similar question here Maybe that can help you as well

chris166
What I had done in the meantime was dynamically create the routes based on board IDs. I don't know that route handlers will do it for me, because they don't actually help construct routes, but it seems like a pretty good way to handle them as they come in. Thanks!
Rob