J'utilise AngularJS pour manipuler un objet parent assez complexe avec des enfants qui doivent se comporter différemment du côté serveur. Basé sur this answer, ce qui semble assez solide, j'ai créé le cas de test ci-dessous. Le problème que je rencontre est que chaque fois que j'entre la fonction CreateModel
, tout appel à bindingContext.ValueProvider.GetValue(key)
renvoie null. J'ai vérifié toutes les valeurs dans le débogueur. Le type d'objet semble être chargé, mais aucune valeur n'a encore été liée.ModelBindingContext.ValueProvider.GetValue (key) retourne toujours null
Mes modèles:
public class Menagerie
{
public Menagerie()
{
Critters = new List<Creature>();
}
public string MakeNoise()
{
return String.Join(" ", Critters.Select(c => c.MakeNoise()));
}
public List<Creature> Critters { get; set; }
}
public class Tiger : Creature
{
public Tiger() { }
public override CreatureType Type => CreatureType.Tiger;
public override string Sound => "ROAR";
}
public class Kitty : Creature
{
public Kitty() { }
public override CreatureType Type => CreatureType.Kitty;
public override string Sound => "meow";
}
public class Creature
{
public Creature() { }
public string Name { get; set; }
public virtual CreatureType Type { get; set; }
public virtual string Sound { get; }
public string MakeNoise()
{
return $"{Name} says {Sound ?? "nothing"}.";
}
public static Type SelectFor(CreatureType type)
{
switch (type)
{
case CreatureType.Tiger:
return typeof(Tiger);
case CreatureType.Kitty:
return typeof(Kitty);
default:
throw new Exception();
}
}
}
public enum CreatureType
{
Tiger,
Kitty,
}
public class CreatureModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
CreatureType creatureType = GetValue<CreatureType>(bindingContext, "Type");
Type model = Creature.SelectFor(creatureType);
Creature instance = (Creature)base.CreateModel(controllerContext, bindingContext, model);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => instance, model);
return instance;
}
private T GetValue<T>(ModelBindingContext bindingContext, string key)
{
ValueProviderResult valueResult = bindingContext.ValueProvider.GetValue(key); // valueResult is null
bindingContext.ModelState.SetModelValue(key, valueResult);
return (T)valueResult.ConvertTo(typeof(T)); // NullReferenceException
}
}
Mon script:
(function() {
'use strict';
angular.module('app', []).controller('CritterController', ['$scope', '$http', function ($scope, $http) {
$http.post('/a/admin/get-menagerie', { }).success(function (data) {
$scope.menagerie = data.menagerie;
});
$scope.makeNoise = function() {
$http.post('/a/admin/make-noise', { menagerie: $scope.menagerie }).success(function (data) {
$scope.message = data.message;
});
}
}]);
})();
choses que j'ai essayé
J'ai essayé juste en utilisant une chaîne pour indiquer le nom de la classe, comme dans this answer et this one. Toutefois, l'appel à bindingContext.ValueProvider.GetValue(key)
renvoie toujours null, ce qui entraîne un NullReferenceException
.
J'ai également vérifié que le modèle est correctement lié. Quand je change mon CreatureModelBinder
à ce qui suit, tout est bien mappé. Mais chaque créature perd son type hérité et devient un Creature
.
public class CreatureModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
return base.CreateModel(controllerContext, bindingContext, modelType);
}
} // MakeNoise returns: "Shere Khan says nothing. Mr. Boots says nothing. Dr. Evil says nothing."