23

Wanted to use the same URL for a GET/PUT/DELETE/POST for a REST based API, but when the only thing different about the Actions is which HTTP verbs it accepts, it considers them to be duplicate!

"Type already defines a member called 'Index' with the same parameter types."

To which I said, so what? This one only accepts GET, this one only accepts POST... should be able to be co-exist right?

How?

MetaGuru
  • 42,847
  • 67
  • 188
  • 294
  • 1
    kind of off-topic, but I'm doing exactly this with FubuMVC, worth checking out if you have the freedom to do so – heisenberg Jun 14 '11 at 18:47

4 Answers4

35

That's not ASP.NET MVC limitation or whatever. It's .NET and how classes work: no matter how hard you try, you cannot have two methods with the same name on the same class which take the same parameters. You could cheat using the [ActionName] attribute:

[HttpGet]
[ActionName("Foo")]
public ActionResult GetMe()
{
   ...
}

[HttpPut]
[ActionName("Foo")]
public ActionResult PutMe()
{
   ...
}

[HttpDelete]
[ActionName("Foo")]
public ActionResult DeleteMe()
{
   ...
}

[HttpPost]
[ActionName("Foo")]
public ActionResult PostMe()
{
   ...
}

Of course in a real RESTFul application the different verbs would take different parameters as well, so you will seldom have such situations.

You may take a look at SimplyRestful for some ideas about how your routes could be organized.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • "the different verbs would take different parameters as well" can you elaborate? I thought /users/[id] was a good URL and could accept GET,POST,PUT,DELETE all just the same... the only difference would be the content of the request, right? – MetaGuru Jun 14 '11 at 19:05
  • @Ryan, no, an action that would respond to a POST request would take the view model thet you are creating as action argument: `[HttpPost]public ActionResult Foo(AModelToCreate model) { ... }` which of course would be different than the GET action which would only need an `id`. – Darin Dimitrov Jun 14 '11 at 19:08
  • ohhh I need to read into that, all I ever have used is pulled variables off the Request object... – MetaGuru Jun 14 '11 at 19:12
  • @Ryan, oooooooooooooooo, you definitely need to read into that. You should never pull variables out of `Request`. How are you handling things like validation, are you manually parsing all those strings into their respective model types? That's what ASP.NET MVC model binding is all about and it is very powerful. – Darin Dimitrov Jun 14 '11 at 19:13
8

While ASP.NET MVC will allow you to have two actions with the same name, .NET won't allow you to have two methods with the same signature - i.e. the same name and parameters.

You will need to name the methods differently use the ActionName attribute to tell ASP.NET MVC that they're actually the same action.

That said, if you're talking about a GET and a POST, this problem will likely go away, as the POST action will take more parameters than the GET and therefore be distinguishable.

So, you need either:

[HttpGet]
public ActionResult ActionName() {...}

[HttpPost, ActionName("ActionName")]
public ActionResult ActionNamePost() {...}

Or:

[HttpGet]
public ActionResult ActionName() {...}

[HttpPost]
public ActionResult ActionName(string aParameter) {...}
Thom
  • 2,643
  • 2
  • 30
  • 33
1

Another option is to have a single method that accepts all and distinguishes between HttpMethod and calls the appropriate code from there. E.g.

            string httpMethod = Request.HttpMethod.ToUpperInvariant();

            switch (httpMethod)
            {
                case "GET":
                    return GetResponse();

                case "POST":
                    return PostResponse();

                default:
                    throw new ApplicationException(string.Format("Unsupported HttpMethod {0}.", httpMethod));
            }
The Coder
  • 4,981
  • 2
  • 29
  • 36
0

As a workaround you can add to one of the methods an extra argument with a default value, just to bypass the limitation and be able to build.

Of course take in mind that this is not the most recommended way of doing things, and also you will have to make clear in your code (by the parameter name or via comments) that this is an extra argument just to allow it to build, and of course make sure that you have decorated your attributes correctly.

yoel halb
  • 12,188
  • 3
  • 57
  • 52