Skip to content

Commit

Permalink
Merge pull request #24 from billbogaiv/add-header-value-provider
Browse files Browse the repository at this point in the history
Add Header ValueProvider
  • Loading branch information
billbogaiv authored Jan 22, 2019
2 parents b17c978 + bca16de commit 78c0c52
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 5 deletions.
6 changes: 4 additions & 2 deletions src/HybridModelBinding/DefaultHybridModelBinder.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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());
}
}
}
6 changes: 4 additions & 2 deletions src/HybridModelBinding/DefaultPassthroughHybridModelBinder.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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());
}
}
}
2 changes: 1 addition & 1 deletion src/HybridModelBinding/HybridModelBinding.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>0.12.0</Version>
<Version>0.13.0</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.1.1" />
Expand Down
82 changes: 82 additions & 0 deletions src/HybridModelBinding/ModelBinding/HeaderValueProvider.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// Modified from https://github.com/aspnet/Mvc/blob/8d66f104f7f2ca42ee8b21f75b0e2b3e1abe2e00/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/QueryStringValueProvider.cs.
/// </summary>
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<string, string> 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);
}
}
}
}
49 changes: 49 additions & 0 deletions src/HybridModelBinding/ModelBinding/HeaderValueProviderFactory.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// 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
/// </summary>
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
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/HybridModelBinding/Source.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down

0 comments on commit 78c0c52

Please sign in to comment.