Voici ma classe de modèle:
public class MyModel
{
public Employees[] MyEmpls{get;set;}
public int Id{get;set;}
public OrgName{get;set;}
}
Passer l'objet de structure JSON ci-dessous avec MyEmpls as empty array
au contrôleur MVC.
["Id":12, "MyEmpls":[], "OrgName":"Kekran Mcran"]
Manette
[HttpPost]
public ActionResult SaveOrg(MyModel model)
{
//model.MyEmpls is null here
}
Je m'attends à mode.MyEmpls
pour être un tableau c # vide, pas un null. Un classeur de modèle personnalisé est-il nécessaire pour obtenir un tableau vide?
Je pense que certaines des autres réponses ont manqué le sens de la question: pourquoi le classeur de modèle MVC par défaut lie-t-il un tableau Json vide à null au lieu d'un tableau C # vide?
Eh bien, je ne peux pas vous dire pourquoi ils ont fait ça, mais je peux vous montrer où cela se produit. La source de MVC peut être trouvée sur CodePlex ici: http://aspnetwebstack.codeplex.com/SourceControl/latest . Le fichier que vous recherchez est ValueProviderResult.cs où vous pouvez voir:
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 partie intéressante est le "cas 3":
else
{
// case 3(a): source is empty array, so can't perform conversion
return null;
}
Vous pouvez contourner ce problème en initialisant votre tableau sur le modèle dans son constructeur. Dans ma lecture rapide de la source, je ne peux pas vous dire pourquoi ils ne peuvent pas retourner un tableau vide ou pourquoi ils décident de ne pas le faire, mais cela devrait rendre la lecture intéressante.
Vous obtenez une valeur nulle car il s'agit de la valeur par défaut pour un type de référence en C #. Pour obtenir un tableau vide, vous devrez initialiser le tableau dans votre modèle à l'aide d'un constructeur. Cependant, comme vous devrez définir la taille du tableau lors de son initialisation, il peut être préférable d'utiliser un autre type de collection tel qu'un 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>();
}
}
Vous obtiendrez alors une liste vide lorsqu'un tableau vide est passé depuis le json.
Si vous devez vraiment utiliser un tableau, il suffit de l'initialiser avec une taille:
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 vous obtenez model.MyEmpls comme null, vous pouvez créer une condition côté serveur pour arrêter de déclencher une exception comme:
if(model.MyEmpls !=null){
...
}
Et vous obtenez la valeur null car votre MyEmpls est un tableau de classe personnalisé et vous envoyez simplement [].
J'espère que cela vous aidera.
vous pouvez définir un setter qui vérifie si la valeur est nulle
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;}
}
Essayez de créer un classeur de modèle comme ci-dessous
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
}
}
}
Dans Application_Start, enregistrez le classeur de modèle
ModelBinders.Binders.Add(typeof(MyModel), new MyModelBinder())
Et modifiez le contrôleur comme
[HttpPost]
public ActionResult SaveOrg([ModelBinder(typeof(MyModelBinder))] MyModel model)
{
//model.MyEmpls is null here
}
[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 désérialise correctement les tableaux vides. Vous pouvez donc ignorer le modèle transmis et le reconstruire à partir du flux de demande d'entrée. Probablement pas de la bonne façon, mais si vous n'avez besoin de le faire qu'une fois, cela économise des efforts. Vous devrez référencer System.Web.Extensions.