私はかなり複雑な親オブジェクトを操作するためにAngularJSを使用しています。子オブジェクトはサーバー側とはかなり異なる動作をする必要があります。非常に堅実に見えるthis answerに基づいて、以下のテストケースを作成しました。私が実行している問題は、CreateModel
関数を入力するたびにbindingContext.ValueProvider.GetValue(key)
への呼び出しがnullを返すことです。私はデバッガのすべての値をチェックしました。オブジェクトタイプがロードされているように見えますが、値はまだバインドされていません。ModelBindingContext.ValueProvider.GetValue(key)は常にnullを返します。
マイモデル:
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
}
}
マイスクリプト:私は
を試してみた
(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;
});
}
}]);
})();
物事私のように、単にクラス名を示すために、文字列を使用して試してみましたthis answerおよびthis oneである。ただし、bindingContext.ValueProvider.GetValue(key)
の呼び出しはnullを返し、結果としてNullReferenceException
となります。
また、モデルが正しくバインドされていることを確認しました。 CreatureModelBinder
を次のように変更すると、すべてがうまくマッピングされます。しかし、各クリーチャーは継承されたタイプを失い、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."