diff --git a/src/HybridModelBinding/DefaultHybridModelBinder.cs b/src/HybridModelBinding/DefaultHybridModelBinder.cs
index 97b0de3..4e30d62 100755
--- a/src/HybridModelBinding/DefaultHybridModelBinder.cs
+++ b/src/HybridModelBinding/DefaultHybridModelBinder.cs
@@ -1,4 +1,5 @@
-using Microsoft.AspNetCore.Mvc.Formatters;
+using HybridModelBinding.ModelBinding;
+using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using System.Collections.Generic;
@@ -23,7 +24,8 @@ public DefaultHybridModelBinder(
.AddModelBinder(Body, new BodyModelBinder(formatters, readerFactory))
.AddValueProviderFactory(Form, new FormValueProviderFactory())
.AddValueProviderFactory(Route, new RouteValueProviderFactory())
- .AddValueProviderFactory(QueryString, new QueryStringValueProviderFactory());
+ .AddValueProviderFactory(QueryString, new QueryStringValueProviderFactory())
+ .AddValueProviderFactory(Header, new HeaderValueProviderFactory());
}
}
}
diff --git a/src/HybridModelBinding/DefaultPassthroughHybridModelBinder.cs b/src/HybridModelBinding/DefaultPassthroughHybridModelBinder.cs
index 05cee3f..3b36722 100644
--- a/src/HybridModelBinding/DefaultPassthroughHybridModelBinder.cs
+++ b/src/HybridModelBinding/DefaultPassthroughHybridModelBinder.cs
@@ -1,4 +1,5 @@
-using Microsoft.AspNetCore.Mvc.Formatters;
+using HybridModelBinding.ModelBinding;
+using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using System.Collections.Generic;
@@ -23,7 +24,8 @@ public DefaultPassthroughHybridModelBinder(
.AddModelBinder(Body, new BodyModelBinder(formatters, readerFactory))
.AddValueProviderFactory(Form, new FormValueProviderFactory())
.AddValueProviderFactory(Route, new RouteValueProviderFactory())
- .AddValueProviderFactory(QueryString, new QueryStringValueProviderFactory());
+ .AddValueProviderFactory(QueryString, new QueryStringValueProviderFactory())
+ .AddValueProviderFactory(Header, new HeaderValueProviderFactory());
}
}
}
diff --git a/src/HybridModelBinding/HybridModelBinding.csproj b/src/HybridModelBinding/HybridModelBinding.csproj
index 2015462..5cd1069 100644
--- a/src/HybridModelBinding/HybridModelBinding.csproj
+++ b/src/HybridModelBinding/HybridModelBinding.csproj
@@ -12,7 +12,7 @@
false
false
true
- 0.12.0
+ 0.13.0
diff --git a/src/HybridModelBinding/ModelBinding/HeaderValueProvider.cs b/src/HybridModelBinding/ModelBinding/HeaderValueProvider.cs
new file mode 100644
index 0000000..6d32935
--- /dev/null
+++ b/src/HybridModelBinding/ModelBinding/HeaderValueProvider.cs
@@ -0,0 +1,82 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Internal;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace HybridModelBinding.ModelBinding
+{
+ ///
+ /// Modified from https://github.com/aspnet/Mvc/blob/8d66f104f7f2ca42ee8b21f75b0e2b3e1abe2e00/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/QueryStringValueProvider.cs.
+ ///
+ public class HeaderValueProvider : BindingSourceValueProvider, IEnumerableValueProvider
+ {
+ public HeaderValueProvider(
+ BindingSource bindingSource,
+ IHeaderDictionary values,
+ CultureInfo culture)
+ : base(bindingSource)
+ {
+ if (bindingSource == null)
+ {
+ throw new ArgumentNullException(nameof(bindingSource));
+ }
+
+ this.values = values ?? throw new ArgumentNullException(nameof(values));
+ Culture = culture;
+ }
+
+ public CultureInfo Culture { get; private set; }
+
+ private readonly IHeaderDictionary values;
+ private PrefixContainer prefixContainer;
+
+ protected PrefixContainer PrefixContainer
+ {
+ get
+ {
+ if (prefixContainer == null)
+ {
+ prefixContainer = new PrefixContainer(values.Keys);
+ }
+
+ return prefixContainer;
+ }
+ }
+
+ public override bool ContainsPrefix(string prefix)
+ {
+ return PrefixContainer.ContainsPrefix(prefix);
+ }
+
+ public virtual IDictionary GetKeysFromPrefix(string prefix)
+ {
+ if (prefix == null)
+ {
+ throw new ArgumentNullException(nameof(prefix));
+ }
+
+ return PrefixContainer.GetKeysFromPrefix(prefix);
+ }
+
+ public override ValueProviderResult GetValue(string key)
+ {
+ if (key == null)
+ {
+ throw new ArgumentNullException(nameof(key));
+ }
+
+ var values = this.values[key];
+
+ if (values.Count == 0)
+ {
+ return ValueProviderResult.None;
+ }
+ else
+ {
+ return new ValueProviderResult(values, Culture);
+ }
+ }
+ }
+}
diff --git a/src/HybridModelBinding/ModelBinding/HeaderValueProviderFactory.cs b/src/HybridModelBinding/ModelBinding/HeaderValueProviderFactory.cs
new file mode 100644
index 0000000..2f807ad
--- /dev/null
+++ b/src/HybridModelBinding/ModelBinding/HeaderValueProviderFactory.cs
@@ -0,0 +1,49 @@
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using System;
+using System.Globalization;
+using System.Threading.Tasks;
+
+namespace HybridModelBinding.ModelBinding
+{
+ public class HeaderValueProviderFactory : IValueProviderFactory
+ {
+ ///
+ /// We need to re-create a Header BindingSource since the default ASP.NET MVC version
+ /// is greedy and that won't work as a ValueProvider.
+ ///
+ /// Ref. https://github.com/aspnet/Mvc/blob/8d66f104f7f2ca42ee8b21f75b0e2b3e1abe2e00/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/BindingSource.cs
+ /// Ref. https://github.com/aspnet/Mvc/blob/8d66f104f7f2ca42ee8b21f75b0e2b3e1abe2e00/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/BindingSourceValueProvider.cs#L41
+ /// ArgumentException: The provided binding source 'Header' is a greedy data source. 'BindingSourceValueProvider' does not support greedy data sources.
/// Parameter name: bindingSource
+ ///
+ private BindingSource Header = new BindingSource(
+ BindingSource.Header.Id,
+ BindingSource.Header.DisplayName,
+ isGreedy: false,
+ isFromRequest: BindingSource.Header.IsFromRequest);
+
+ public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ var headers = context.ActionContext.HttpContext.Request.Headers;
+ if (headers != null && headers.Count > 0)
+ {
+ var valueProvider = new HeaderValueProvider(
+ Header,
+ headers,
+ CultureInfo.InvariantCulture);
+
+ context.ValueProviders.Add(valueProvider);
+ }
+
+#if NET451
+ return Task.FromResult(0);
+#else
+ return Task.CompletedTask;
+#endif
+ }
+ }
+}
diff --git a/src/HybridModelBinding/Source.cs b/src/HybridModelBinding/Source.cs
index bd8cc3f..ecb7da6 100755
--- a/src/HybridModelBinding/Source.cs
+++ b/src/HybridModelBinding/Source.cs
@@ -4,6 +4,7 @@ public static class Source
{
public const string Body = nameof(Body);
public const string Form = nameof(Form);
+ public const string Header = nameof(Header);
public const string QueryString = nameof(QueryString);
public const string Route = nameof(Route);
}