2011-06-14 14 views
23

Quería utilizar la misma URL para GET/PUT/DELETE/POST para una API basada en REST, pero cuando lo único diferente de las acciones es qué verbos HTTP acepta, ¡los considera duplicados!¿Cómo puedo sobrecargar Acciones ASP.NET MVC basadas en los verbos HTTP aceptados?

"El tipo ya define un miembro llamado 'Índice' con los mismos tipos de parámetros."

A lo que dije, ¿y qué? Este solo acepta GET, este solo acepta POST ... debería ser capaz de coexistir ¿verdad?

¿Cómo?

+1

tipo de fuera de tema, pero estoy haciendo exactamente esto con FubuMVC, vale la pena comprobar si tiene la libertad de hacerlo así – heisenberg

Respuesta

35

Eso no es limitación de ASP.NET MVC o lo que sea. Es .NET y cómo funcionan las clases: no importa cuánto lo intentes, no puedes tener dos métodos con el mismo nombre en la misma clase que tomen los mismos parámetros. Se podría hacer trampas con el atributo [ActionName]:

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

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

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

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

Por supuesto, en una aplicación real reparador las diferentes verbos tomarían diferentes parámetros, así, por lo que rara vez tendrá este tipo de situaciones.

Puede echar un vistazo a SimplyRestful para obtener algunas ideas sobre cómo se pueden organizar sus rutas.

+0

"los diferentes verbos tomarían diferentes parámetros también" ¿me pueden dar más detalles? Pensé que/users/[id] era una buena URL y podría aceptar GET, POST, PUT, DELETE todo igual ... la única diferencia sería el contenido de la solicitud, ¿no? – BigOmega

+0

@Ryan, no, una acción que respondería a una solicitud POST tomaría el modelo de vista que está creando como argumento de acción: '[HttpPost] public ActionResult Foo (modelo AModelToCreate) {...}' que por supuesto sería diferente de la acción GET que solo necesitaría un 'id'. –

+0

ohhh Necesito leer sobre eso, todo lo que he usado es sacar variables del objeto Request ... – BigOmega

8

Mientras que ASP.NET MVC le permitirá tener dos acciones con el mismo nombre, .NET no le permitirá tener dos métodos con la misma firma, es decir, el mismo nombre y parámetros.

Deberá nombrar los métodos de manera diferente utilizando el atributo ActionName para decirle a ASP.NET MVC que en realidad son la misma acción.

Dicho esto, si estamos hablando de un GET y una POST, este problema es probable que se vaya, ya que la acción se llevará a POST más parámetros que el GET y por lo tanto ser distinguibles.

Por lo tanto, es necesario o bien:

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

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

O:

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

[HttpPost] 
public ActionResult ActionName(string aParameter) {...} 
1

Otra opción es tener un único método que acepta todas y distingue entre HTTPMethod y llama al código correspondiente de allí. P.ej.

  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)); 
      } 
+2

Uso inteligente de HttpMethod, pero viola SRP. – Rap

0

Como solución alternativa se pueden agregar a uno de los métodos de un argumento extra con un valor por defecto, sólo para eludir la limitación y será capaz de construir.

Por supuesto, tenga en cuenta que esta no es la forma más recomendada de hacer las cosas, y también tendrá que dejar en claro en su código (por el nombre del parámetro o mediante comentarios) que este es un argumento adicional para permitir para construir, y por supuesto asegúrese de haber decorado sus atributos correctamente.

Cuestiones relacionadas