Skip to content

Instantly share code, notes, and snippets.

@pitermarx
Created June 4, 2021 10:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pitermarx/0932aa40ce84f391c332e93e59617e64 to your computer and use it in GitHub Desktop.
Save pitermarx/0932aa40ce84f391c332e93e59617e64 to your computer and use it in GitHub Desktop.
Cake Model Binding
using System.ComponentModel;
// Uses cake Configuration to bind a model
// Configuration values should come from
// 1 - CAKE_ prefixed env vars
// 2 - cake.config files
// 3 - cmdline arguments
class NaiveModelBinder
{
private readonly Func<string, string> getValue;
private readonly Action<string> log;
public NaiveModelBinder(ICakeContext context)
{
this.getValue = context.Configuration.GetValue;
this.log = context.Debug;
}
public T Bind<T>()
{
log($"\nBinding configuration values to model {typeof(T).Name}");
return (T)this.Bind(typeof(T));
}
private object Bind(Type type, string prefix = "")
{
var props = type.GetProperties();
var instance = Activator.CreateInstance(type);
foreach (var prop in props)
{
if (TryGetValue(prop.PropertyType, prop.Name, prefix, out var value))
{
if (prop.PropertyType == typeof(string) || !prop.PropertyType.IsClass)
{
log($"{(prefix + prop.Name).Replace("_", ".")}={value}");
}
prop.SetValue(instance, value);
}
}
return instance;
}
private bool TryGetValue(Type type, string name, string prefix, out object value)
{
var stringValue = this.getValue(prefix + name);
if (type == typeof(string))
{
value = stringValue;
return stringValue != null;
}
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
return TryGetValue(Nullable.GetUnderlyingType(type), name, prefix, out value);
}
if (type.IsClass)
{
value = Bind(type, prefix + name + "_");
return true;
}
if (string.IsNullOrEmpty(stringValue))
{
value = null;
return false;
}
value = TypeDescriptor
.GetConverter(type)
.ConvertFromInvariantString(stringValue);
return true;
}
}
T Bind<T>() => new NaiveModelBinder(Context).Bind<T>();
@pitermarx
Copy link
Author

Example usage
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment