0

I have controller BlogController with a couple of actions:

1)Index(string id) - show all posts/show single post if parameter id specified
2)New() - add new post
3)Delete() - delete post
4)And some more another actions

So if i type in browser mysite/blog i could see all posts if i type mysite/blog/postnameid i want to see single post.

the problem is when i type mysite/blog/postnameid it is not working (The resource cannot be found.), but if i type mysite/blog/index/postnameid this way it is working. How could i make mysite/blog/postnameidto work as well.

Here is my blog route in global.ascx

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

 routes.MapRouteLowercase(
               "Blog", // Route name
               "Blog/{action}/{id}", // URL with parameters
               new { controller = "Blog", action = "Index" } // Parameter defaults
            );

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

Than if i change it like that

routes.MapRouteLowercase(
               "Blog", // Route name
               "Blog/{id}", // URL with parameters
               new { controller = "Blog", action = "Index" } // Parameter defaults
            );

the mysite/blog/postnameid working but all another actions like New(), Delete() stop working after that (The resource cannot be found. )

UPDATE: I forgot to mention that id is sting, not int. so from @Darin answer i changed new { id = @"\w+" } to new { id = @"\d+" } and all seams to be working but now when i typed blog/new for example, it is routing to show/new insteard blog/new

1 Answer 1

2

It is a bad idea and against RESTful conventions to have a single controller action that do 2 things and of course violating the single responsibility principle (list all posts if no id is specified and show a given post if an id is specified). The correct way would be to have the following:

  • /blog => BlogController/Index => list all posts
  • /blog/123 => BlogController/Show(id = 123) => show details of a given post
  • /blog/new => BlogController/New() => start writing a new post
  • /blog/delete/123 => BlogController/Delete(id = 123) => delete given post

which would be achieved with the following routes:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Blog",
        "blog/{id}",
        new { controller = "Blog", action = "Show" },
        new { id = @"\d+" }
    );

    routes.MapRoute(
        "Default",
        "blog/{action}/{id}",
        new { controller = "Blog", action = "Index", id = UrlParameter.Optional }
    );
}

Notice the required route constraint on the first definition which indicates what form all ids must be so that the routing engine could disambiguate between an id and an action name.

This being said if you want to violate the 2 principles I mentioned earlier and have the routes you want a slight adaptation would be required:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Blog",
        "blog/{id}",
        new { controller = "Blog", action = "Index" },
        new { id = @"\d+" }
    );

    routes.MapRoute(
        "Default",
        "blog/{action}/{id}",
        new { controller = "Blog", action = "Index", id = UrlParameter.Optional }
    );
}

Now:

  • /blog => BlogController/Index(id = null) => list all posts
  • /blog/123 => BlogController/Index(id = 123) => show details of a given post
  • /blog/new => BlogController/New() => start writing a new post
  • /blog/delete/123 => BlogController/Delete(id = 123) => delete given post
Sign up to request clarification or add additional context in comments.

8 Comments

interesting thanks for such detailed reply, so default route it will be handling only blog stuff, but if i would need to have another similar to blog route behaviour, in such case i cant have two "Default" route mapping isn't it?
the url /blog cannot be mapped to two different default routes, that would be impossible and doesn't make sense. You can however have another route like /page which would default to the default page or something. Also per Darin's suggestions I would only make one difference and name the routes that lists the posts as /posts. Or if you have an area named "blog" then it would be /blog/posts. I like the s at the end to indicate multiplicity
some moere details, my id is stirng, but when i type int it worked /blog/123, but blog/slagurl not, how could i get it worked with string param?
@jason, string patterns are problematic as the routing engine cannot disambiguate between /blog/slagurl and /blog/new. He cannot know that in the first case you are talking about an id and in the second about an action name. Route constraints such as \d+ work only if they allow you to disambiguate your urls. It seems that this is not your case. So in order to solve this problem you could write a custom Route by deriving from the Route class and override the GetRouteData method.
i was looking in to NBlog http://nblog.codeplex.com/, they have something similar, but they using a bit different routes definitions, i could't have the same like they have i think.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.