Skip to content

Commit 1633e6d

Browse files
committed
Add minimal API model binding
1 parent 09a98f4 commit 1633e6d

4 files changed

Lines changed: 123 additions & 4 deletions

File tree

samples/WebAPINet8MinimalFluent/Program.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@
4444

4545
app.UseHttpsRedirection();
4646

47-
app.MapGet("/posts", async ([FromServices] BlogContext blogContext, [FromQuery] IReadOnlyCollection<ISortParticle<Post>> sorts, [FromQuery] IReadOnlyCollection<IFilterParticle<Post>> filters) =>
47+
app.MapGet("/posts", async (
48+
[FromServices] BlogContext blogContext,
49+
SortParticles<Post> sorts,
50+
FilterParticles<Post> filters) =>
4851
{
4952
blogContext.Database.EnsureCreated();
5053
var result = await blogContext.Posts

samples/WebApiNet9MinimalFluent/Program.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@
4343
app.UseHttpsRedirection();
4444

4545
app.MapGet("/posts", async (
46-
[FromServices] BlogContext blogContext,
47-
[FromQuery] IReadOnlyCollection<ISortParticle<Post>> sorts,
48-
[FromQuery] IReadOnlyCollection<IFilterParticle<Post>> filters
46+
[FromServices] BlogContext blogContext,
47+
SortParticles<Post> sorts,
48+
FilterParticles<Post> filters
4949
) =>
5050
{
5151
blogContext.Database.EnsureCreated();

src/Minimal/FilterParticles.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using Microsoft.AspNetCore.Http;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using Microsoft.Extensions.Primitives;
4+
using System;
5+
using System.Collections;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Reflection;
9+
using System.Threading.Tasks;
10+
11+
namespace Panner.AspNetCore
12+
{
13+
public sealed class FilterParticles<TEntity> : IReadOnlyCollection<IFilterParticle<TEntity>>
14+
where TEntity : class
15+
{
16+
private readonly IReadOnlyCollection<IFilterParticle<TEntity>> _particles;
17+
18+
private FilterParticles(IReadOnlyCollection<IFilterParticle<TEntity>> particles)
19+
{
20+
_particles = particles;
21+
}
22+
23+
public static ValueTask<FilterParticles<TEntity>> BindAsync(HttpContext context, ParameterInfo parameter)
24+
{
25+
if (context == null)
26+
{
27+
throw new ArgumentNullException(nameof(context));
28+
}
29+
if (parameter == null)
30+
{
31+
throw new ArgumentNullException(nameof(parameter));
32+
}
33+
34+
var queryName = parameter.Name ?? "filters";
35+
StringValues value = context.Request.Query[queryName];
36+
37+
var pContext = context.RequestServices.GetRequiredService<IPContext>();
38+
39+
if (StringValues.IsNullOrEmpty(value))
40+
{
41+
return ValueTask.FromResult(new FilterParticles<TEntity>(Array.Empty<IFilterParticle<TEntity>>()));
42+
}
43+
44+
if (!pContext.TryParseCsv(value.ToString(), out IEnumerable<IFilterParticle<TEntity>> particles))
45+
{
46+
throw new InvalidOperationException("Could not parse provided filters.");
47+
}
48+
49+
return ValueTask.FromResult(new FilterParticles<TEntity>(particles.ToArray()));
50+
}
51+
52+
public int Count => _particles.Count;
53+
public IEnumerator<IFilterParticle<TEntity>> GetEnumerator() => _particles.GetEnumerator();
54+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
55+
56+
public IReadOnlyCollection<IFilterParticle<TEntity>> Value => _particles;
57+
}
58+
}

src/Minimal/SortParticles.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using Microsoft.AspNetCore.Http;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using Microsoft.Extensions.Primitives;
4+
using System;
5+
using System.Collections;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Reflection;
9+
using System.Threading.Tasks;
10+
11+
namespace Panner.AspNetCore
12+
{
13+
public sealed class SortParticles<TEntity> : IReadOnlyCollection<ISortParticle<TEntity>>
14+
where TEntity : class
15+
{
16+
private readonly IReadOnlyCollection<ISortParticle<TEntity>> _particles;
17+
18+
private SortParticles(IReadOnlyCollection<ISortParticle<TEntity>> particles)
19+
{
20+
_particles = particles;
21+
}
22+
23+
public static ValueTask<SortParticles<TEntity>> BindAsync(HttpContext context, ParameterInfo parameter)
24+
{
25+
if (context == null)
26+
{
27+
throw new ArgumentNullException(nameof(context));
28+
}
29+
if (parameter == null)
30+
{
31+
throw new ArgumentNullException(nameof(parameter));
32+
}
33+
34+
var queryName = parameter.Name ?? "sorts";
35+
StringValues value = context.Request.Query[queryName];
36+
37+
var pContext = context.RequestServices.GetRequiredService<IPContext>();
38+
39+
if (StringValues.IsNullOrEmpty(value))
40+
{
41+
return ValueTask.FromResult(new SortParticles<TEntity>(Array.Empty<ISortParticle<TEntity>>()));
42+
}
43+
44+
if (!pContext.TryParseCsv(value.ToString(), out IEnumerable<ISortParticle<TEntity>> particles))
45+
{
46+
throw new InvalidOperationException("Could not parse provided sorts.");
47+
}
48+
49+
return ValueTask.FromResult(new SortParticles<TEntity>(particles.ToArray()));
50+
}
51+
52+
public int Count => _particles.Count;
53+
public IEnumerator<ISortParticle<TEntity>> GetEnumerator() => _particles.GetEnumerator();
54+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
55+
56+
public IReadOnlyCollection<ISortParticle<TEntity>> Value => _particles;
57+
}
58+
}

0 commit comments

Comments
 (0)