抽象クラスのバインダーを作成しようとしています。バインダーは、使用するクラスの実装を決定します。
public abstract class Pet
{
public string name { get; set; }
public string species { get; set; }
abstract public string talk { get; }
}
public class Dog : Pet
{
override public string talk { get { return "Bark!"; } }
}
public class Cat : Pet
{
override public string talk { get { return "Miaow."; } }
}
public class Livestock : Pet
{
override public string talk { get { return "Mooo. Mooo. Fear me."; } }
}
だから私はペットを連れて行くコントローラーを持っています、バインダーはそれが犬、猫、家畜のどれであるかを(種のひもに応じて)決定します。
public class PetBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var values = (ValueProviderCollection)bindingContext.ValueProvider;
var name = (string)values.GetValue("name").ConvertTo(typeof(string));
var species = (string)values.GetValue("species").ConvertTo(typeof(string));
if (species == "dog")
{
return new Dog { name = name, species = "dog" };
}
else if (species == "cat")
{
return new Cat { name = name, species = "cat" };
}
else
{
return new Livestock { name = name, species = species };
}
}
}
public class HomeController : Controller
{
public JsonResult WorksFine(Pet pet)
{
return Json(pet);
}
public JsonResult DoesntWork(List<Pet> pets)
{
return Json(pets);
}
}
これはうまく機能しますが、ペットが別の構造(List<Pet>
または別のオブジェクトなど)に入るとすぐに、NullReferenceException(var name = (string)values.GetValue("name").ConvertTo(typeof(string));
PetBinderの行)が発生します。私は何が間違っているのですか?
テストするPersonクラスを追加しました。また、NullReferenceExceptionが発生しました。
public class Person
{
public string name { get; set; }
public Pet pet { get; set; }
}
public class HomeController : Controller
{
public JsonResult PersonAction(Person p)
{
return Json(p);
}
}
ccurrensは、var name = (string)values.GetValue("name").ConvertTo(typeof(string));
nullが返された理由は、リストから値を取得できなかったためだと述べました。
名前が付けられているのはわかりますが、オブジェクト内の場合は名前が付けられ[n].name
、[n].species
単一の場合は名前が付けられているだけです。List<Pet>
Person
pet.name
pet.species
Pet
name
species
解決
[n]
の正しいプレフィックス(またはpet
その他)を持つパラメーター名を取得するためにGetValue
、次のコードを使用しました。
bool hasPrefix = bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName);
string prefix = ((hasPrefix)&&(bindingContext.ModelName!="")) ? bindingContext.ModelName + "." : "";
誰かが興味を持っているなら、私はこの答えDefaultModelBinder
に似たものを使うことから継承することになりました。これが私が使用した完全なコードです:
public class DefaultPetBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext,ModelBindingContext bindingContext,Type modelType)
{
//https://stackoverflow.com/questions/5460081/asp-net-mvc-3-defaultmodelbinder-inheritance-problem
bool hasPrefix = bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName);
string prefix = ((hasPrefix)&&(bindingContext.ModelName!="")) ? bindingContext.ModelName + "." : "";
// get the parameter species
ValueProviderResult result;
result = bindingContext.ValueProvider.GetValue(prefix+"species");
if (result.AttemptedValue.Equals("cat"))
return base.CreateModel(controllerContext,bindingContext,typeof(Cat));
else if (result.AttemptedValue.Equals("dog"))
return base.CreateModel(controllerContext,bindingContext,typeof(Dog));
return base.CreateModel(controllerContext, bindingContext, typeof(Livestock)); // livestock
}
}