views:

119

answers:

3

I'm currently building a site which has a bunch of main categories and in each category you can perform a search.

Basically, I want my addresses to work like this...

When the website loads (as in when someone goes to www.mySite.com) it will redirect them to the default category.

www.mySite.com/Category

Then when you search within a category, the results would come up in a page like the following.

www.mySite.com/Category/Search

I want to put everything in one controller and have one main view for the Category and one for the Search, I would then render these based on which category is currently being viewed.

Can this be done, maybe with routing? I don't want to have to create a different controller for each category as it's just duplicating a lot of the code.

A: 

Yes, routing can save you here.

You can either add a bunch of Actions to your Controller, or in routing, you can do something like this:

routeCollection.MapRoute("Category1", "Category/Category1", new { controller = "Category", action = "Search", id = "Category1" });
routeCollection.MapRoute("Category2", "Category/Category2", new { controller = "Category", action = "Search", id = "Category2" });
routeCollection.MapRoute("Category3", "Category/Category3", new { controller = "Category", action = "Search", id = "Category3" });

and so on. I assume you have a list of categories from a data store, and if so, you can just loop through them adding categories as you see above.

Let me know if this doesn't make sense, or I didn't solve your problem, as I'm not 100% sure what you're going for here :)

CubanX
A: 

Yes, it can be done through routing.

Something like:

routers.MapRoute(
   "Category",
   "Category/[action]",
   new { controller = "Category", action = "Index", category = 1 });
Lazarus
A: 

If you want to limit yourself to only on possible controller you can do this:

routes.MapRoute(
            "Default", // Route name
            "{category}/{action}/{id}", // URL with parameters
            new { controller = "Categories", category="DefaultCategory", action = "Index", id = UrlParameter.Optional } 
        );

If you do it this way you can address different controllers:

routes.MapRoute(
            "Default", // Route name
            "{controller}/{category}/{id}/{action}", // URL with parameters
            new { controller = "Home", category="DefaultCategory", action = "Index", id = UrlParameter.Optional } 
        );

Based on your comment you would have do go in this direction:

routes.MapRoute(
            "Categories",
            "{category}/{action}",
            new { controller = "Categories", action = "Index" },
            new
            {
                category=
            new FromValuesListConstraint("Category1", "Category2", "Category3", "Category4", "Category5")
            }
            );

// all your default routing
routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );

FromValuesListContraint is only a sample for the simplest case if you have only a few categories. If you have dynamic categories that come out of a database you have to do a different implementation, but still can follow my example with IRoutecontraints.

Here is the Sample IRouteConstraints Implementation (FromValuesListConstraint):

public class FromValuesListConstraint : IRouteConstraint
{
    private List<string>_values;

    public FromValuesListConstraint(params string[] values)
    {
        this._values = values.Select(x => x.ToLower()).ToList();
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        string value = values[parameterName].ToString();

        return _values.Contains(value.ToLower());
    }
}

The reason why you have to do this whole IRoutConstraint thing here is otherwise you would not be able to use you default route because a request for www.mysite.com/mycontroller or www.mysite.com/mycontroller/myaction would match the categories route.

chbu
This works /// routes.MapRoute("Categories", "{Category}/{action}", new { controller = "Category", action = "Index" }) /// But none of my other controllers work now. Is there a way to have exactly this structure for my Category pages but also have all my other controllers work (example: Account/Login or About/FAQ, etc.)? For the categories route I dont't want to use {controller}. Thanks
sheefy
You may have to move this route below your other routes to allow actions on other controllers to pass through.
KOTJMF
Thanks, works great.
sheefy
KOTJMF: That is not possible. If he just moves his route below a {controller}/{action}/{id} style default route the default route will match. Always move the most specific routes in the beginning of your routes and the most generic (default route) should be at the end.
chbu