2011-06-25 19 views
14

Estoy tratando de tener dos métodos diferentes para el registro de cuenta en mi aplicación Asp.net MVC, uno para usuarios generales para registrarse y otro para usuarios que se están registrando con un token de registro específico. Por lo tanto tengo las siguientes firmas de método en mi AccountController:¿Por qué Asp.net MVC no puede distinguir entre dos acciones cuando tienen diferentes parámetros?

public virtual ActionResult Register() {...} 

public virtual ActionResult Register (Guid registrationToken) {...} 

Sin embargo, cuando voy a http://localhost/Account/Register me sale una excepción que la solicitud actual es ambigua entre estas dos acciones. Tenía la impresión de que usaría la acción Register sin parámetros si no se pasaba el parámetro registrationToken GET, de lo contrario utilizaría la 2da.

¿Esto requiere una configuración de ruta especial?

Respuesta

14

¿Sería más fácil tener un método con un parámetro que acepta valores NULL? Esto también resolverá automáticamente su problema ya que no será ambiguo:

public virtual ActionResult Register (Guid? registrationToken) 
{ 
    if(registrationToken.HasValue) 
    { 
     // this is specific user 
    }   
    else 
    { 
     // this is general user 
    } 
} 
+0

Sí, esa es una solución, pero esperaba una solución que fue automatizada por MVC. Solo pensé que MVC podía distinguir entre acciones por parámetros. – KallDrexx

+2

@KallDrexx: el problema es que no distingue entre 'ningún parámetro' y 'el parámetro es nulo'. Además, no se diferenciará entre 'parámetro' a 'y' el parámetro 'b' es nulo 'y' parágrafo' a' se establece y no hay parámetro 'b' '. Aunque podría parecer obvio para casos simples, esto no es fácil de implementar para casos más complicados. Este sería un marco de toma de decisiones muy complicado y propenso a errores. –

+0

Eso tiene sentido – KallDrexx

3

¿El segundo método requiere publicación? Por lo general, es beneficioso agregar [HttpPost] sobre cualquier método que se utilizará para aceptar el envío de un formulario.

Y también puede resolver su problema.

+0

No, ambos métodos están destinados a presentar un formulario de registro para el usuario. El último es para una forma más especializada, mientras que el primero es para una forma general. – KallDrexx

+0

en ese caso, no veo por qué estás tratando de darles el mismo nombre. –

11

La clase base predeterminada para los controladores mvc, Controller usa ActionInvoker para seleccionar qué acción invocar. Primero, la acción es seleccionada, por defecto del valor RouteData ["acción"], y luego se produce todo el enlace y validación del modelo para los parámetros de la acción seleccionada. Es por eso que cuando el invocador ve dos acciones con el mismo nombre y los mismos atributos para seleccionar, se dispara el error, ya que no puede distinguir entre dos.

Pero hay una forma integrada de gestionar la lógica de selección de acciones, es decir, mediante el uso de atributos derivados de ActionMethodSelector class. Primero creas una clase derivada de ella, que contiene lógica para invocar la acción. En su caso

sería utilizar la acción sin parámetros Registro si no había registrationToken GET parámetro pasado en , de lo contrario sería utilizar el segundo.

public class RegistrationActionTokenAttribute : ActionMethodSelectorAttribute 
    { 
     public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo) 
     { 
      if (controllerContext.HttpContext.Request.QueryString.AllKeys.Contains("registrationToken")) 
      { 
       return true; 
      } 
      return false; 
     } 
    } 

que implementan la lógica demostrativa de que la segunda acción se debe marcar válida para la selección, si cadena de consulta contiene el parámetro "registrationToken". Lo único que queda es decorar su segundo método con este atributo

[RegistrationActionToken]  
public virtual ActionResult Register (Guid registrationToken) {...} 

Y el error se ha ido. Además, el controlador ahora selecciona la acción correcta, según el parámetro de cadena de consulta

+0

Me gusta esta solución en teoría, y no sabía que pudiera hacer esto, pero me temo que se convierta en una pesadilla de mantenimiento. Si alguien cambia el nombre del 'registrationToken' y no modifica el atributo, se producirán errores que pueden no ser fáciles de probar por la unidad. – KallDrexx

+0

Esta es la forma integrada de controlar la selección de acciones. En general, puede pasar el nombre del parámetro con el constructor del atributo para hacer más obvio que el atributo depende de los parámetros de la acción. – archil

+0

Ese es un buen punto acerca de configurarlo para aceptar la cadena de consulta a través de los parámetros del atributo. – KallDrexx

Cuestiones relacionadas