2009-06-05 12 views
6

Tengo una pregunta sobre cómo obtener la característica de listado en blanco y negro del UpdateModel/TryUpdateModel del controlador MVC para trabajar en propiedades individuales de objetos secundarios. Por ejemplo, supongamos que tengo un cuestionario que recopila detalles sobre la persona que completa el formulario y sobre su empresa.¿Cómo incluir en la lista blanca o en la lista negra los campos del objeto hijo en el método ModelBinder/UpdateModel?

Mi [simplificada] campos de formulario serían nombrados, por ejemplo:

YourName 
YourEmail 
Company.Name 
Company.Phone 

Ahora en mi modelo, digamos que no quiero Company.ID o Company.IsPremiumMember a ser manipulados, por lo que Me gustaría excluirlos de la vinculación del modelo. Probé una combinación de listas blancas, listas negras y ambas para lograr que esto funcione. No he tenido ningún éxito. Esto es lo que me estoy encontrando:

Cuando explícitamente incluyo en mi lista blanca los mismos cuatro nombres de campo que escribí anteriormente, toda la Compañía no queda limitada (es decir, el cuestionario.La compañía se deja nula) a menos que también incluya "Empresa "en mi lista blanca. Pero esto tiene el efecto indeseable de vincular a TODA la empresa, y no solo las dos propiedades que quiero.

Entonces, traté de incluir Company.ID y Company.IsPremiumMember en mi lista negra, pero esto parece ser superado por la lista blanca y no filtra estas propiedades "después del hecho", supongo.

Sé que hay otras maneras de expresar la "bindabilidad", como a través del atributo [Bind] en los miembros, pero esto no es ideal ya que me gustaría tener las mismas clases de modelo utilizadas en otras situaciones con diferentes reglas vinculantes, como permitir que un administrador establezca las propiedades que desee.

Espero una respuesta obvia es que debería escribir mi propia carpeta modelo, y ya he empezado a tratar de cómo hacer esto, pero realmente estaba esperando usar un "fuera de la caja "solución para lo que (en mi opinión) parece un escenario muy común. Otra idea que estoy reflexionando es fabricar mi propio diccionario ValueProvider a mano para el método UpdateModel, pero de nuevo, algo que preferiría evitar si hay una manera más fácil.

¡Gracias por cualquier ayuda! -Mike


Adición # 1

Éstos son los campos que presento en mi formulario:

YourName 
YourEmail 
Company.Name 
Company.Phone

Y aquí es lo que un sombrero negro envía mi camino :

[email protected]&Company.Name=ACME+Corp&Company.Phone=555-555-5555&Company.CreditLimit=10000000

(! Asegúrese observa el parámetro adicional que le agrega allí al final)

Y aquí está el problema:

Mientras Iniciado, no parece posible (mediante el Carpeta de modelo predeterminada) para evitar que se establezca CreditLimit --- es la Compañía completa o nada --- sin una gran solución. ¿Me equivoco?


Adición # 2

estoy bastante convencido ahora que el simple objetivo que tengo no es posible "fuera de la caja." Mi solución ha sido recorrer los campos de formulario publicados y construir mi propio diccionario ValueProvider, lo que permite incluir en la lista blanca los campos que quiero permitir y entregarlos a UpdateModel.


Adición # 3

todavía aún no ha obtenido AutoMapper, pero con algo parecido a la mano, la solución de crear algunos ViewModels/DTO para manejar este tipo de complejo whitelisting- - más la capacidad de adjuntar fácilmente la misma validación del lado del servidor (FluentValidation) que ya estoy usando en mis objetos de dominio --- parece una solución viable. ¡Gracias a todos!

Respuesta

1

En general, el mejor camino a seguir es crear vista-modelos, los modelos construidos específicamente para sus puntos de vista. Estos modelos son no objetos de dominio. Son objetos de transferencia de datos, creados para transferir datos de las acciones de su controlador a sus plantillas de visualización. Puede usar una herramienta como AutoMapper sin problemas para crear/actualizar un objeto de modelo de dominio desde su objeto de modelo de visualización o para crear/actualizar un objeto de modelo de vista desde su modelo de dominio.

+0

AutoMapper parece una excelente utilidad que de hecho simplifica esto. Voy a verlo más tarde esta noche. ¡Gracias! – Funka

+1

También he encontrado que UpdateModel viene en forma genérica, UpdateModel , que encontré en otra publicación aquí en S.O. que recomienda crear una interfaz T que pueda actuar como una lista blanca. No vi esta técnica en ninguno de los libros de MVC que he leído, pero parece que podría ser prometedor. (Tal vez no sea más esfuerzo que crear un puñado de DTO.) P.S. esta otra publicación a la que hice referencia está aquí: http://stackoverflow.com/questions/924424/difference-using-updatemodel-and-modelbinding-in-parameter – Funka

+0

Si usa el patrón de modelo de vista, también puede realizar un potente servidor- Validación lateral en el modelo de vista estrictamente tipado (en lugar de en los campos Request.Form o FormCollection) utilizando bibliotecas como Castle.Components.Validator o FluentValidation. – yfeldblum

1

He trabajado alrededor de este problema haciendo que la acción de aceptar dos objetos (el padre y el objeto secundario)

Ejemplo:
Supongamos que tenemos el siguiente modelo:

public class Employee 
    { 
     public string Name { get; set; } 
     public int Age { get; set; } 
     public Company Comapany { get; set; } 
    } 
    public class Company 
    { 
     public int Phone { get; set; } 
    } 

a construir su formulario como el siguiente:

<form action="Home/Create" method="post"> 
    <label for="Employee.Name">Name</label> 
    <%=Html.TextBox("Employee.Name") %><br /> 
    <label for="Employee.Name">Age</label>  
    <%=Html.TextBox("Employee.Age") %><br /> 
    <label for="Employee.Name">Comapany Phone</label>  
    <%=Html.TextBox("Company.Phone") %><br /> 
    <input type="submit" value="Send" /> 
    </form> 

luego construir una acción de "Crear" que aceptan dos objetos uno de tipo Emplear ee y el otro de tipo Comapny y asignar el objeto de la empresa a la propiedad Employee.Company dentro de la acción:

public ActionResult Create(Employee employee,Company company) 
     { 
      employee.Comapany = company; 
      UpdateModel(employee); 
      return View(); 
     } 

espero que esto ayude.

Editar:

public ActionResult Create(Employee employee,Company company) 
{ 
    employee.Comapany = company; 
    UpdateModel(employee,new[] {"Name","Email","Phone"}); 
    return View(); 
} 
+0

Gracias por Tu respuesta.Sin embargo, no estoy teniendo ningún problema para vincular el modelo: mi problema es tratar de restringir lo que en el modelo se limita. Parece que en su ejemplo, sin suministrar ninguna lista blanca o lista negra (u otro equivalente) al método UpdateModel, alguien aún podría establecer Company.IsPremiumMember inyectando esto en su publicación de formulario. – Funka

+0

Luego, la solución es pasar la lista de propiedades que desea incluir al método UpdateModel. Voy a actualizar mi respuesta –

+0

He añadido una adición a mi publicación original. (Ver especialmente la última línea.) El problema más apropiadamente parece ser un "todo o nada" en la propiedad de la Compañía ... – Funka

0

¿Ha intentado utilizar la siguiente ?:

ActionResult pública Crear ([bind (Excluir = "PropertyToExclude1, PropertyToExclude2")] empleado Empleado) {

// código de acción aquí

}

o utilice Incluir en lugar de Excluir para enumerar qué campos se pueden enlazar en lugar de cuáles no pueden

+0

Hola, como se muestra en mi publicación original, el problema no es que no pueda excluir "PropertyToExclude1". El problema es que no puedo excluir "SomeParent.SomeProperty" de esta manera. – Funka

+0

¡Qué desastre! – Aaron

Cuestiones relacionadas