2009-10-09 9 views
6

Hay un montón de post muy bueno y las explicaciones de cómo implementar la validación con ASP.NET MVC, y yo prefiero uno de estos:

Sin embargo, realmente me gusta llamar a ActionMethods a través del método jquery $ .ajax. Una de las razones por las que quiero usar $ .ajax es porque habrá muchas vistas parciales cargadas dinámicamente en la página (incluso el formulario para la creación de entidades) a través de llamadas $ .ajax y no puedo simplemente devolver la vista: Perderé todo el contenido cargado dinámicamente.

Para que tenga una mejor visión del problema, publicaré un código simple para explicar cómo me gustaría llamar a las acciones de los controladores y manejar las respuestas en el código jquery del cliente.

Los controladores ActionMethod:

public ActionResult CreateCustomer(string name, string accountNumber) 
    { 
     try 
     { 
      CustomerService.InsertCustomer(name, accountNumber); 

      return Json(new ActionInfo() 
      { 
       Success = true, 
       Message = "Customer Is Successfully Created" 
      }); 

     } 
     catch (Exception ex) 
     { 
      return Json(new ActionInfo() 
      { 
       Success = false, 
       Message = ex.Message 
      }); 
     } 
    } 

Calling y gastos de envío en el código de cliente:

$.ajax({ 
type: "POST", 
url: $form.attr('action'),// /MyController/CreateCustomer 
data: $form.serialize(), 
error: HandleUnespectedError, 
dataType: "json", 
success: function(response) { 

    if (response.Success) 
     alert("Success: " + response.Message); 
    else 
     alert("Error: " + response.Message); 
}}); 

¿Hay una buena manera de hacer que algunos de estos marcos de validación para trabajar de la manera que necesito? Sé que puedo agregar errores de validación en ActionInfo, y luego manejarlo en el cliente, pero creo que eso ya sería la base de mi validación.

Respuesta

5

He tenido un gran éxito haciendo la validación a través de AJAX utilizando atributos de anotaciones de datos. Para verificar la validez de sus datos, querrá usar la propiedad ModelState del controlador, que tiene una propiedad propia llamada IsValid. Recomiendo echar un vistazo al data annotations validation attributes tutorial del sitio oficial ASP.NET MVC.

En primer lugar, querrá modificar la acción de su controlador para aceptar su objeto modelo como parámetro, en lugar de un nombre y número de cuenta separados. Esto hará que realizar la validación, que demostraré a continuación, sea mucho más simple. Según su ejemplo, mi mejor estimación es que su objeto modelo es, o se llamaría, Cliente. Es posible que tenga el código siguiente para definir el objeto de modelo y su acción del controlador ...

// model object 
public class Customer 
{ 
    public Int32 Id {get; set;} 
    public String Name {get; set;} 
    public String AccountNumber {get; set;} 
} 

// controller 
public class CustomerController : Controller 
{ 
    public ActionResult CreateCustomer([Bind(Exclude = "Id")] Customer customer) 
    { 
    // controller action code 
    } 
} 


Asegúrese de que sus campos de formulario se nombran para que coincida con los nombres de las propiedades del objeto al cliente para ASP .NET MVC puede unirlos automágicamente. El atributo "Vincular", en este caso, le indica a ASP.NET MVC que ignore la propiedad "Id" de la clase Cliente cuando vincula los campos de formulario a las propiedades del modelo. Como este es un cliente nuevo, todavía no tenemos una identificación, por lo que podemos dejar el ID de forma segura como el valor predeterminado y abandonar la capa de datos para descubrir la mejor manera de generarlo.

Una vez que el controlador ha construido el objeto modelo para el método de acción, su validez se puede verificar fácilmente a través de la propiedad ModelState.IsValid. Como cabría esperar, volverá a ser verdadero si las propiedades del modelo son válidas, o falso si 1 o más propiedades no son válidas.

De la pregunta original, parece que el método CustomerService.InsertCustomer arroja excepciones cuando falla la validación.Esto es completamente innecesario. InsertCustomer solo debería realizar las operaciones de datos necesarias para insertar el nuevo registro. A menos que desee abstraer excepciones específicas de la implementación, como SqlException, InsertCustomer no debería realmente necesitar capturar o lanzar ninguna excepción, pero lo más probable es que permita que todas las excepciones pasen al controlador (o quien quiera que sea la persona que llama).

El resultado final de todo esto, puede haber una acción de controlador que se parece a lo siguiente:

public ActionResult CreateCustomer([Bind(Exclude = "Id")] Customer customer) 
{ 
    // model is invalid 
    if (!ModelState.IsValid) 
    { 
    return Json(new ActionInfo() 
    { 
     Success = false, 
     Message = "Validation failed" // you will probably want a more robust message :-) 
    }); 
    } 

    // service method accepts a Customer object rather than arbitrary strings 
    CustomerService.InsertCustomer(customer); 

    return Json(new ActionInfo() 
    { 
    Success = true, 
    Message = "Customer created successfully." 
    }); 

} 


Si desea reportar errores inesperados, como excepciones relacionadas con bases de datos, entonces ciertamente puede agregar un bloque try/catch alrededor de la llamada a InsertCustomer, y devolver el resultado necesario para mostrar el mensaje de error al cliente.

+0

¡Hey thedude! Muchas gracias por el esfuerzo :) Estoy totalmente de acuerdo con usted por la entidad del Cliente para el enlace (quería hacer eso, no sé por qué había puesto el método con parámetros simples) y para el manejo de excepciones con seguridad. Con xVal puedo implementar fácilmente la validación del cliente, y si alguien lo evita lo veré en acción. Pero, ¿cómo presentaría los mensajes de validación junto a los campos en ese caso? –

+0

Para eso, le gustaría devolver una vista parcial en lugar de JSON desde la acción de su controlador. En su vista parcial, usaría el método de ayuda Html.ValidationMessage() para mostrar un mensaje de error para cada campo. Los mensajes de error de nivel de campo que generaron sus atributos de anotaciones de datos están disponibles para su controlador a través de la propiedad 'ModeloEstado'. Por ejemplo, para obtener el primer mensaje de error para un campo llamado name, lo obtendría a través de 'ModelState ['Name']. Errors [0] .ErrorMessage'. Además, eche un vistazo al método 'Ajax.BeginForm'. Lo he usado con gran éxito en el pasado. –

+1

Eso es lo que me di cuenta, o bien devolveré a JSON una vista parcial, y eso es lo que no me gusta ... Sin embargo, voy a echar un vistazo a cómo manejarlo usando MS incorporada en las funciones de Ajax, aunque mi deseo era evitar eso :) Gracias –

2

Esto es más de un año después de haber pedido a su pregunta, pero me ha cubierto validación del lado del servidor con llamadas Ajax en mi blog post que pueda ser de mucho interés para usted. Veo que devuelve resultados fallidos como llamadas HTTP exitosas. He manejado esto de manera diferente (creo que es más correcto ya que $.ajax tiene la capacidad de success y error funcionalidad de respuesta). Y su ejemplo particular es un ejemplo perfecto que podría implementarse con la funcionalidad que explico en mi publicación de blog.

Básicamente, en lugar de devolver siempre una respuesta exitosa (pero con las propiedades configuradas para decirle al cliente que el procesamiento del lado del servidor falló) prefiero lanzar una excepción en el servidor y manejarla en consecuencia en el cliente. Estoy usando una clase ModelStateException personalizada junto con un filtro de acción HandleModelStateException.

Cuestiones relacionadas