【问题标题】:NullReferenceException when using custom model binder使用自定义模型绑定器时出现 NullReferenceException
【发布时间】:2011-07-27 18:03:37
【问题描述】:

我正在尝试为抽象类制作活页夹。绑定器决定使用哪个类的实现。

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&lt;Pet&gt; 或另一个对象),我就会得到一个 NullReferenceException(在 PetBinder 中的 var name = (string)values.GetValue("name").ConvertTo(typeof(string)); 行上)。我做错了什么?

我添加了一个 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 的原因是因为它无法从列表中获取值。

我看到它们在 List&lt;Pet&gt; 中时被命名为 [n].name[n].species,但是在 Person 对象中时它们被命名为 pet.namepet.species 并且当它们在单个 Pet 中时,它们只是命名为namespecies

解决方案

要获取GetValue 的正确前缀([n]pet 或其他任何名称)的参数名称,我使用了以下代码:

bool hasPrefix = bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName);
string prefix = ((hasPrefix)&&(bindingContext.ModelName!="")) ? bindingContext.ModelName + "." : "";

如果有人感兴趣,我最终使用类似于 answer 的东西从 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
    }  

}

【问题讨论】:

    标签: c# asp.net-mvc-3 model-binding custom-model-binder


    【解决方案1】:

    在您收到错误的那一行中,values 可能为 null,或者 GetValue("name") 返回的内容可能为 null。

    我假设当您调用 List&lt;Pet&gt; 方法时,ValueProvider 将返回整个 List 而不是每个单独的 Pet,因此它无法获取值 "name",因为它没有存在于List 类中。

    如果没有看到更多代码,我无法确定。

    【讨论】:

    • 您的意思是要查看堆栈跟踪吗?除了在 Global.asax 中添加PetBinder 之外,没有其他内容。我创建了一个带有名称和单个Pet 的Person 类,在调试器中我看到ValueProvider 中的属性被命名为pet.name,所以我输入了GetValue(bindingContext.ModelName + ".name"),它在列表中返回未定义(属性是 [n].name[n].species) 以及 Person 对象中的正确答案。我应该如何以始终有效的方式获取属性?
    猜你喜欢
    • 2012-07-31
    • 1970-01-01
    • 2012-11-28
    • 1970-01-01
    • 1970-01-01
    • 2018-08-22
    • 2018-10-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多