Skip to content

Instantly share code, notes, and snippets.

@jnm2
Last active August 29, 2015 14:23
Show Gist options
  • Save jnm2/d94f679f1c4a57ec655b to your computer and use it in GitHub Desktop.
Save jnm2/d94f679f1c4a57ec655b to your computer and use it in GitHub Desktop.
Provides a fluent API to map discriminator property values to derived types and handle MVC model deserialization.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
public class DerivedDiscriminatorModelBinder<T> : DefaultModelBinder where T : class
{
private readonly string discriminatorPropertyName;
private readonly Dictionary<object, Type> mapping = new Dictionary<object, Type>();
public DerivedDiscriminatorModelBinder(string discriminatorPropertyName)
{
this.discriminatorPropertyName = discriminatorPropertyName;
}
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType == typeof(T))
{
var discriminatorValue = bindingContext.ValueProvider.GetValue(CreateSubPropertyName(bindingContext.ModelName, discriminatorPropertyName));
if (discriminatorValue == null)
throw new Exception("Discriminator property '" + discriminatorPropertyName + "' does not exist.");
Type derivedType;
var lookupValue = discriminatorValue.RawValue ?? DBNull.Value;
if (!mapping.TryGetValue(lookupValue, out derivedType))
try
{
return base.BindModel(controllerContext, bindingContext);
}
catch
{
throw new Exception((lookupValue == DBNull.Value ? "Null discriminator value" : "Discriminator value '" + discriminatorValue.RawValue + "'") + " is not mapped to a derived type and the base type cannot be instantiated.");
}
var model = Activator.CreateInstance(derivedType);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, derivedType);
}
return base.BindModel(controllerContext, bindingContext);
}
public DerivedDiscriminatorModelBinder<T> Map<TDerived>(object discriminatorPropertyValue)
where TDerived : T, new()
{
mapping.Add(discriminatorPropertyValue ?? DBNull.Value, typeof(TDerived));
return this;
}
}
public static class ModelBindersExtensions
{
public static DerivedDiscriminatorModelBinder<T> AddDerivedDiscriminator<T>(this ModelBinderDictionary modelBinderDictionary, string discriminatorPropertyName) where T : class
{
var r = new DerivedDiscriminatorModelBinder<T>(discriminatorPropertyName);
modelBinderDictionary.Add(typeof(T), r);
return r;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment