Skip to content

Instantly share code, notes, and snippets.

@kierenj
Created March 1, 2018 14:31
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 kierenj/4806198f7857a3d18c5f52de89584a06 to your computer and use it in GitHub Desktop.
Save kierenj/4806198f7857a3d18c5f52de89584a06 to your computer and use it in GitHub Desktop.
// the attribute itself - to put against our action parameters.
// combines the model binding engine with our value provider factory.
public class FromHeaderAttribute : ParameterBindingAttribute
{
public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
{
var httpConfig = parameter.Configuration;
var binder = new ModelBinderAttribute()
.GetModelBinder(httpConfig, parameter.ParameterType);
return new ModelBinderParameterBinding(
parameter, binder,
new ValueProviderFactory[] { new HeaderValueProviderFactory() });
}
}
// factory for creating our custom value provider class given a specific action
// context. this is where we capture and keep reference to the HTTP headers
// for the request .
public class HeaderValueProviderFactory : ValueProviderFactory
{
public override IValueProvider GetValueProvider(HttpActionContext actionContext)
{
return new HeaderValueProvider(actionContext.Request.Headers);
}
}
// Our value provider, which handles the bulk of the work
public class HeaderValueProvider : IValueProvider
{
private readonly HttpRequestHeaders _headers;
public HeaderValueProvider(HttpRequestHeaders headers)
{
_headers = headers;
}
public bool ContainsPrefix(string prefix)
{
// all prefixes are flattened - all members and sub-members
// considered equally
return true;
}
// the heart of the approach. this will be called for each property of the
// model we’re binding to – we need only find and return the appropriate
// values
public ValueProviderResult GetValue(string key)
{
IEnumerable values;
var propName = RemovePrefixes(key);
var headerName = MakeHeaderName(propName);
if (!_headers.TryGetValues(headerName, out values))
{
return null;
}
var data = string.Join(",", values.ToArray());
return new ValueProviderResult(values, data, CultureInfo.InvariantCulture);
}
private static string RemovePrefixes(string key)
{
var lastDot = key.LastIndexOf('.');
if (lastDot == -1) return key;
return key.Substring(lastDot + 1);
}
// here’s the simple algorithm for making a HTTP header name out of our members:
// iterate through the characters, inserting a dash before uppercase letters,
// with the exception of the first character
private static string MakeHeaderName(string key)
{
var headerBuilder = new StringBuilder();
for (int i = 0; i < key.Length; i++)
{
if (char.IsUpper(key[i]) && i > 0)
{
headerBuilder.Append('-');
}
headerBuilder.Append(key[i]);
}
return headerBuilder.ToString();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment