JSON пользовательский связыватель null для производного абстрактного класса asp.net mvc - PullRequest
1 голос
/ 01 августа 2011

Я сделал пользовательское связующее для абстрактного класса. Связующее решает, какую реализацию использовать. Это работает хорошо, но когда я добавляю свойство, которое не существует в абстрактном классе, в дочерний класс, оно всегда равно null.

Вот код для абстрактного класса Pet и производных классов Dog и Cat.

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 string parasite { get;set; } 
}


public class DefaultPetBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext,ModelBindingContext bindingContext,Type modelType)
    {
        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")){
            //var model = base.CreateModel(controllerContext, bindingContext, typeof(Cat));
            return base.CreateModel(controllerContext,bindingContext,typeof(Cat));
        }
        else (result.AttemptedValue.Equals("dog"))
        {
            return base.CreateModel(controllerContext,bindingContext,typeof(Dog));
        }
    }
}

Контроллер просто принимает параметр Pet и возвращает его как JSON.

Если я отправлю

{name:"Odie", species:"dog"}

Я вернусь

{"talk":"Bark!","name":"Odie","species":"dog"}

Для Cat существует свойство паразита, которого нет в абстрактном классе Pet. Если я отправлю

{"parasite":"cockroaches","name":"Oggy","species":"cat"}

я вернусь

{"talk":"Miaow.","parasite":null,"name":"Oggy","species":"cat"}

Я пробовал это с другими более сложными классами, это просто простой пример. Я посмотрел в отладчике, значение parasite находится в поставщике значений, модель, которую возвращает связыватель, содержит поле для паразита. Кто-нибудь может увидеть, где проблема?

1 Ответ

5 голосов
/ 02 августа 2011

Попробуй так:

protected override object CreateModel(ControllerContext controllerContext,ModelBindingContext bindingContext,Type modelType)
{
    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")) 
    {
        var model = Activator.CreateInstance(typeof(Cat));
        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(Cat));
        return model;
    }
    else if (result.AttemptedValue.Equals("dog"))
    {
        var model = Activator.CreateInstance(typeof(Dog));
        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(Dog));
        return model;
    }

    throw new Exception(string.Format("Unknown type \"{0}\"", result.AttemptedValue));
}
...