Last active
August 29, 2015 14:23
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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