asp.net-mvcasp.net-mvc-3typeconvertereditortemplates

Cannot use TypeConverter and custom display/editor template together?


The scenario

Suppose I have the following two model classes:

public class ProductColor
{
    public long Id { get; set; }
    public string Name { get; set; }
}

public class Product
{
    public long Id { get; set; }
    public string Name { get; set; }

    public long ProductColorId { get; set; }
    public virtual ProductColor ProductColor { get; set; }
}

Now in a form for creating a new product, I might have this line for the color field...

@Html.EditorFor(model => model.ProductColor)

I want this to generate a drop-down of colors, so I create a custom editor template...

@model MyProject.Models.ProductColor
@using (var db = new MyProject.Models.MyDbContext())
{
    @Html.DropDownList("", new SelectList(db.ProductColors, "Id", "Name", Model))
}

Up to here, this works. But now if I submit this create form, I get this validation error:

The parameter conversion from type 'System.String' to type 'MyProject.Models.ProductColor' failed because no type converter can convert between these types.

Of course this is because the HTTP request contains the color ID as a string (e.g. "1") and one would need some code to turn that into an actual ProductColor instance. So I wrote a TypeConverter...

[TypeConverter(typeof(ProductColor.PCTypeConverter))]
public class ProductColor
{
    public long Id { get; set; }
    public string Name { get; set; }

    public class PCTypeConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(string) ? true : base.CanConvertFrom(context, sourceType);
        }
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value.GetType() == typeof(string))
                using (var db = new MyDbContext())
                    return db.ProductColors.Find(Convert.ToInt64(value));
            return base.ConvertFrom(context, culture, value);
        }
    }
}

Now submitting the request works fine as expected, but the custom editor template no longer does. It just doesn’t get invoked. The system thinks that my type is basically like string and just generates a textbox.

The problem

I cannot get both to work. Either I have a type converter, in which case I don’t get the drop-down (because the custom editor template never gets invoked), or I don’t have a type converter, in which case validation fails when the request is submitted.

What is the correct solution to this?


Solution