Provides the ability to bind models using both ModelBinder and ValueProvider in ASP.NET Core.
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
samples/AspNetCoreWebApplication
src/HybridModelBinding Increment version Nov 29, 2018
.gitignore
HybridModelBinding.sln Add ASP.NET Core sample Jul 19, 2018
LICENSE
README.md

README.md

HybridModelBinding

For those who want the utmost flexibility in model binding.

Note: this README is a WIP.

The hybrid approach differs from traditional model binding since you get to work with both IModelBinder and IValueProvider. This means your model can first get bound with data from the body of a request, and then potentially get updated with data from route or querystring-attributes (in that order). This has the most benefit for users who prefer to have one-model for their request representations. To avoid unexpected model-values, value providers by default, are not bound unless the model's properties are properly attribute-decorated.

Examples

ASP.NET Core 2.1

dotnet add package HybridModelBinding

Startup.cs

// Boilerplate...

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc()
        .AddHybridModelBinder();
}

Model

using HybridModelBinding;

public class IndexModel
{
    [From(Source.Body, Source.QueryString, Source.Route)]
    public int? Age { get; set; }

    // Specific re-ordering to show `route` comes first!
    [From(Source.Body, Source.Form, Source.Route, Source.QueryString)]
    public string Name { get; set; }
}

Controller

[HttpGet]
[Route("{age?}/{name?}")]
public IActionResult Index(IndexModel model)
{ }

View

<h3>Age: @(Model.Age.HasValue ? Model.Age.ToString() : "N/A")</h3>
<h3>Name: @(string.IsNullOrEmpty(Model.Name) ? "N/A" : Model.Name)</h3>

By adding the convention-instance, any controller-action with one-parameter will automatically get associated with the hybrid binder. DefaultHybridModelBinderProvider is built-in and is setup to bind data in the following order: body => form-values => route-values => querystring-values. If you do not want to use the convention, you can also decorate your model-parameter with [From].

Results

Based on the setup above, here is how various URIs will get parsed/rendered:

/

<h3>Age: N/A</h3>
<h3>Name: N/A</h3>

/10

<h3>Age: 10</h3>
<h3>Name: N/A</h3>

/10/Bill

<h3>Age: 10</h3>
<h3>Name: Bill</h3>

/10/Bill?age=20

<h3>Age: 20</h3>
<h3>Name: Bill</h3>

/10/Bill?age=20&name=Boga

<h3>Age: 20</h3>
<h3>Name: Bill</h3> <!--note how the querystring does not get bound since the route comes first in the [From...] ordering-->