1

I know there a many Q&A's on here regarding MVC routing. Unfortunately, I am still having some issues regarding routing that I don't understand.

First and Foremost - Can I have onverloaded ActionResults in my Controller?

For example, I make a 3 requests to the same controller/action with different parameters.

  • "/MyController/DoSomething"
  • "/MyController/DoSomething/[Guid String]
  • "/MyController/DoSomething/[Guid String]/TypeA

... and in the controller I have these methods

public ActionResult DoSomething()
{
    ViewBag.Title = "Do Something By Default";
    return View();
}

public ActionResult DoSomething(String id)
{
    ViewBag.Title = "Do Something By id";
    return View();
}

public ActionResult DoSomething(String id, String type)
{
    ViewBag.Title = "Do Something By id and type";
    return View();
}

I would expect each overloaded method to do it's thing - but it doesn't. The only ActionMethod being invoked is DoSomething() regardless of the parameters I enter. In short, the DoSomething(String id) and DoSomething(String id, String type) are completely ignored.

Even when I attempted this...

public ActionResult DoSomething(String? id)
{
     ViewBag.Title = "Do Something Conditionally";
     return View();
}

...just to see what would happen. A compilation error is thrown

Error 4 The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable'

NOTE: My parameters are strings (technically GUIDs) - not integers.

I figured perhaps I needed to map these routes in the /App_Start/RouteConfig class and tried this just to see if I could get one overloaded method to work

routes.MapRoute(
   "MyController",
   "MyController/DoSomething/{id}",
   new { controller = "MyController", action = "DoSomething", id = "" }
);

...and still the DoSomething(String id) ActionResult was not invoked. No errors, no exceptions. It was if I did not even have that MapRoute specified.

Is there something I am missing here? Any insight, instruction, guidance you can provide would be greatly appreciated.

tereško
  • 58,060
  • 25
  • 98
  • 150
Sean Mc
  • 83
  • 1
  • 8
  • 1
    No, routing does not work this way. You can achieve what you want, but it's a bit more involved, and requires the use of routing constraints, and other factors. I don't have time right now to explain this, but hopefully others will. MVC only allows one action method per HTTP verb (get, post, etc..) for any given method.. So you can have Index() and Index(string x) but they must be different verbs. This is a limitation of the model binding mechanism. MVC doesn't know which overload to choose because there are no types associated with HTTP form fields or querystrings. – Erik Funkenbusch Feb 06 '15 at 01:03
  • Well - I guess that settles that. Thanks Erik - I appreciate your insight. I will look into routing constraints to see if I can work around this. – Sean Mc Feb 06 '15 at 17:09
  • Okay, well I was able to get certain aspects of this to work that will certainly help. It turns out that in I have an ActionResult with a parameter e.g.: DoSomething(String id) and I do not have a DoSomething() ActionResult method - I can use this method with or without the parameter conditionally. I have only tested it with strings but it does work. This will certainly suffice for using the same action and view for new forms for inserts and pre-populated forms for updates. – Sean Mc Feb 06 '15 at 18:20
  • On a separate note, the reason why `String?` is invalid is because `String` is a reference type -- it's already nullable. You can only wrap value types in a `Nullable<>` object because they can't hold `null` by themselves. – Blindy Feb 06 '15 at 18:40

1 Answers1

0

To effectively accomplish this - all that is required is to identify what parameters you are working with and apply default values in the event the parameters are null. Ultimately this will result in a single action. In the case of the above example - removing the DoSomething() and DoSomething(String id) and working only within the confines of the DoSomething(String id, String type)

Example

public ActionResult DoSomething(String id, String type)
{
    var _id = String.Empty
    var _type = String.Empty

    if(id != null)
    {
        _id = id
    }

    if(type != null)
    {
       _type = type
    }

    ViewBag.Title = "Do Something By id and type conditionally";
    return View();
}

When the following requests are made, they will all work according to logical conditions within the single action.

  • "/MyController/DoSomething"
  • "/MyController/DoSomething/[Guid String]
  • "/MyController/DoSomething/[Guid String]/TypeA
Sean Mc
  • 83
  • 1
  • 8
  • Yes, this is a fine way to handle this. type will be null if the parameter is not specified (assuming you make the parameter optional in your route) Although, you cannot have a type if you do not have an id.. so not sure if that is a requirement. – Erik Funkenbusch Feb 06 '15 at 18:45