query pass parameter net mvc fromuri frombody from body asp c# asp.net-mvc json wcf model-binding

c# - pass - mvc web api query string parameters



Pasar una matriz JS vacĂ­a al controlador da nulo (7)

Aquí está mi modelo, que es una clase Proxy WCF

public class MyModel { public Employees[] MyEmpls{get;set;} public int Id{get;set;} public OrgName{get;set;} }

Pasando por debajo de un objeto de estructura json con MyEmpls as empty array al controlador MVC.

["Id":12, "MyEmpls":[], "OrgName":"Kekran Mcran"]

Controlador

[HttpPost] public ActionResult SaveOrg(MyModel model) { //model.MyEmpls is null here }

Estoy esperando mode.MyEmpls como una matriz c # vacía y no nula. ¿Podría alguien ayudarme aquí? ¿Necesitamos escribir una carpeta de modelo personalizada para esto?


Creo que algunas de las otras respuestas han pasado por alto el significado de la pregunta: ¿por qué el encuadernador de modelos MVC por defecto vincula una matriz Json vacía a nula en lugar de una matriz C # vacía?

Bueno, no puedo decirte por qué lo hicieron, pero puedo mostrarte dónde sucede. La fuente de MVC se puede encontrar en CodePlex aquí: http://aspnetwebstack.codeplex.com/SourceControl/latest . El archivo que está buscando es ValueProviderResult.cs donde puede ver:

private static object UnwrapPossibleArrayType(CultureInfo culture, object value, Type destinationType) { if (value == null || destinationType.IsInstanceOfType(value)) { return value; } // array conversion results in four cases, as below Array valueAsArray = value as Array; if (destinationType.IsArray) { Type destinationElementType = destinationType.GetElementType(); if (valueAsArray != null) { // case 1: both destination + source type are arrays, so convert each element IList converted = Array.CreateInstance(destinationElementType, valueAsArray.Length); for (int i = 0; i < valueAsArray.Length; i++) { converted[i] = ConvertSimpleType(culture, valueAsArray.GetValue(i), destinationElementType); } return converted; } else { // case 2: destination type is array but source is single element, so wrap element in array + convert object element = ConvertSimpleType(culture, value, destinationElementType); IList converted = Array.CreateInstance(destinationElementType, 1); converted[0] = element; return converted; } } else if (valueAsArray != null) { // case 3: destination type is single element but source is array, so extract first element + convert if (valueAsArray.Length > 0) { value = valueAsArray.GetValue(0); return ConvertSimpleType(culture, value, destinationType); } else { // case 3(a): source is empty array, so can''t perform conversion return null; } } // case 4: both destination + source type are single elements, so convert return ConvertSimpleType(culture, value, destinationType); } }

La parte interesante es "caso 3":

else { // case 3(a): source is empty array, so can''t perform conversion return null; }

Puede eludir este problema inicializando su matriz en el modelo en su constructor. En mi lectura rápida de la fuente, no puedo decirte por qué no pueden devolver una matriz vacía o por qué deciden no hacerlo, pero debería ser una lectura interesante.


El comportamiento predeterminado de la inicialización de la matriz C # es anular la matriz no vacía

Entonces, si envía una matriz vacía, no iniciará una matriz vacía, sino que activará la inicialización predeterminada como nula

Vea el siguiente enlace http://www.dotnetperls.com/null-array


Intenta crear un archivador modelo como se muestra a continuación

public class MyModelBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { try { var request = controllerContext.HttpContext.Request; return new MyModel { MyEmpls = request[] ?? new Employees[0], Id = request["Id"] ?? "", OrgName = request["OrgName"] ?? "" }; } catch { //do required exception handling } } }

En Application_Start, registre el archivador modelo

ModelBinders.Binders.Add(typeof(MyModel), new MyModelBinder())

Y modifique el controlador como

[HttpPost] public ActionResult SaveOrg([ModelBinder(typeof(MyModelBinder))] MyModel model) { //model.MyEmpls is null here }


Obtiene un valor nulo ya que este es el valor predeterminado para un tipo de referencia en C #. Para obtener una matriz vacía, deberá inicializar la matriz en su modelo utilizando un constructor. Sin embargo, como deberá definir el tamaño de la matriz cuando se inicialice, podría ser mejor usar otro tipo de colección, como una List :

public class MyModel { public List<Employees> MyEmpls{get;set;} public int Id{get;set;} public OrgName{get;set;} public MyModel() { MyEmpls = new List<Employees>(); } }

A continuación, obtendrá una lista vacía cuando se pase una matriz vacía desde el json.

Si realmente tiene que usar una matriz, simplemente inicialícela con un tamaño:

public class MyModel { public Employees[] MyEmpls{get;set;} public int Id{get;set;} public OrgName{get;set;} public MyModel() { MyEmpls = new Employees[//enter size of array in here]; } }


Si obtiene el modelo.MyEmpls como nulo, entonces puede crear una condición en el lado del servidor para detener el aumento de excepción como:

if(model.MyEmpls !=null){ ... }

Y lo obtiene nulo porque su MyEmpls es una matriz de clase personalizada y está enviando solo [].

Espero que esto te ayude.


puedes definir un setter que verifica si el valor es nulo

public class MyModel { private _myEmpls{get;set;} public Employees[] MyEmpls{ get{return _myEmpls;} set{_myEmpls=(value==null?new List<Employees>():value);} } public int Id{get;set;} public OrgName{get;set;} }


[HttpPost] public ActionResult SaveOrg(MyModel model) { var serializer = new JavaScriptSerializer(); var stream = System.Web.HttpContext.Current.Request.InputStream; var reader = new StreamReader(stream); stream.Position = 0; var json = reader.ReadToEnd(); model= serializer.Deserialize<MyModel>(json); //model.MyEmpls is [] here }

JavaScriptSerializer deserializa matrices vacías correctamente. Por lo tanto, puede ignorar el modelo pasado y reconstruirlo desde la secuencia de solicitud de entrada. Probablemente no de la manera correcta, pero si solo necesitas hacerlo una vez, ahorra un poco de esfuerzo. Tendrá que hacer referencia a System.Web.Extensions.