Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I'm rewriting the question, as the answers so far show me that I have not defined it good enough. I'll leave the original question for reference below.

When you set up your routing you can specify defaults for different url/route parts. Let's consider example that VS wizard generates:

        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "DefaultPage", action = "Index", id = UrlParameter.Optional } // Parameter defaults

In this example if controller is not specified, DefaultPageController will be used and if action is not specified "Index" action will be used. The urls will generally look like: http://mysite/MyController/MyAction.

If there is no action in Url like this: http://mysite/MyController then the index action will be used.

Now let's assume I have two actions in my controller Index and AnotherAction. The urls that correspond to them are http://mysite/MyController and http://mysite/MyController/AnotherAction respectively. My "Index" action accepts a parameter, id. So If I need to pass a parameter to my Index action, I can do this: http://mysite/MyController/Index/123. Note, that unlike in URL http://mysite/MyController, I have to specify the Index action explicitly. What I want to do is to be able to pass http://mysite/MyController/123 instead of http://mysite/MyController/Index/123. I do not need "Index" in this URL I want the mvc engine to recognize, that when I ask for http://mysite/MyController/123, that 123 is not an action (because I have not defined an action with this name), but a parameter to my default action "Index". How do I set up routing to achieve this?

Below is the original wording of the question.


I have a controller with two methods definded like this

    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Index(SomeFormData data)
    {
        return View();

    }

This allows me to process Url like http://website/Page both when the user navigates to this url (GET) and when they subsequently post back the form (POST).

Now, when I process the post back, in some cases I want to redirect the browser to this url:

http://website/Page/123

Where 123 is some integer, and I need a method to process this url in my controller.

How do I set up the routing, so this works? Currently I have "default" routing generated by the wizard like this:

        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "DefaultPage", action = "Index", id = UrlParameter.Optional } // Parameter defaults

I tried adding another controller method like this:

public ActionResult Index(int id)
{
    return View();
}

But this doesn't work as ambiguous action exception is thrown:

The current request for action 'Index' on controller type 'PageController' is ambiguous between the following action methods: System.Web.Mvc.ActionResult Index() on type PageController System.Web.Mvc.ActionResult Index(Int32) on type PageController

I must add, that I also have other actions in this controller. This would have worked if I didn't.

share|improve this question

5 Answers 5

up vote 4 down vote accepted

Here is how this can be resoled:

You can create a route constraint, to indicate to the routing engine, that if you have something in url that looks like a number (123) then this is an action parameter for the default action and if you have something that does not look like a number (AnotherAction) then it's an action.

Consider This code:

routes.MapRoute(
  "MyController", "MyController/{productId}", 
  new {controller="My", action="Index"}, 
  new {productId = @"\d+" });

This route definition will only match numeric values after MyController in http://mysite/MyController/123 so it will not interfere with calling another action on the same controller.

Source: Creating a Route Constraint

share|improve this answer
1  
I had the exact same problem. Controller was "/Profile/xxxxx" where XXXX could be a username on my site, or another method in the profile controller. Route constraints didn't quite work b/c all XXX are alpha. Instead I created a "/Profiles/{Username}" route (notice pluralization) and mapped Profiles --> Profile controller. –  EBarr Apr 15 '11 at 18:31
    
Nice! Thank you, for sharing! –  zespri Apr 15 '11 at 20:48

If you keep the variable name to remain being ID, you don't need to change anything.

Rename the post one to "PostIndex" and add this attribute:

[ActionName("Index")]

Same question on SO here.

Ok, here's a cut/paste answer for you, if that helps.

public ActionResult Index()    {        
return View();    
}    
[AcceptVerbs(HttpVerbs.Post), ActionName("Index")]   
public ActionResult PostIndex(SomeFormData data)    {        
return View();    
}
share|improve this answer
    
As I'm mentioning in the question, I'm getting an exception in this case. Here is the text: The current request for action 'Index' on controller type 'ActionController' is ambiguous between the following action methods: System.Web.Mvc.ActionResult Index() on type ActionController System.Web.Mvc.ActionResult Index(Int32) on type ActionController –  zespri Apr 8 '11 at 7:06
    
There is no problem with the post method. Post method is working just fine. It's get for default action and non-default parameter, that gives me trouble. –  zespri Apr 8 '11 at 7:10
    
I understand, but it's because you have duplicate names. Rename the POST one as explained and give it the ActionName property of Index. –  NKCSS Apr 8 '11 at 7:12
    
If it's easier for you, ignore the post action altogether. The question is still valid even if it's not present at all. I'm mentioning it in the question to give more complete picture. –  zespri Apr 8 '11 at 7:12
    
Unless you clarify what SomeData is, and show it working, we won't be able to help. You need a way to differentiate. If it normally is a string, and you want to respond differently when it's an integer, you can only use 1 Action. In that action, do the integer test yourself & return the apropriate view accordingly. –  NKCSS Apr 8 '11 at 7:15

Oh i got it now. I think It's not possible with default route, You need to map custom routes.

    // /MyController/AnotherAction
    routes.MapRoute(
        null,
        "MyController/AnotherAction",
        new { controller = "DefaultPage", action = "AnotherAction" }
    );

    // /MyController
    // /MyController/id
    routes.MapRoute(
        null,
        "MyController/{id}",
        new { controller = "DefaultPage", action = "Index", id = UrlParameter.Optional }
    );

ps. Default routes like /MyController/id must mapped at last.

share|improve this answer
    
Thank you, however this does not work either. When I try to get website/Page/123 I get a error, that there is no action, called 123. I suspect that it's possible to change routing somehow to make asp.net mvc understand that 123 is not an action, but rather a parameter for the default action, but I do not know how. This is what I would like to know. –  zespri Apr 8 '11 at 8:51
1  
Yep, that's closer. It does require to specify each action separately though. In the article that I found (see me answer) they use constraint based on a regular expression. This way, you don't need to specify all the other actions that you have. Thank you very much, for your input. +1 –  zespri Apr 10 '11 at 7:20
    
Uh, I didn't know that -- I mapped all actions in my route because of this. Constraint's looks like awesome. Thank you for letting me know. –  cem Apr 10 '11 at 16:25

You can use the same method as your post back, but accepting a nullable int Id:

public ActionResult Index()
{
    return View();
}

[HttpPost]
public ActionResult Index(int? id, SomeFormData data)
{
    return View();
}

I believe this will allow you to retrieve the id and use it accordingly. If the id exists, you can redirect to another route, or handle the id on the same action.

Hope this helps! :)

share|improve this answer
1  
Why would you pass a nullable id and SomeFormData? This should all be included within the viewmodel I would of thought –  Andi Apr 8 '11 at 8:44

I think you want return the same view, but you need understand you are doing two differents things. One is receive post, and another is accessing by get, and another is accessing by get and parameter...

You should do 3 actionresult with different names, and return de same view as View("ThisIsTheResult")

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.