前言
上回说到,我们实现了IntArrayModelBinder
,可以让 ASP.NET Core 绑定查询字符串中的数组。但是必须显示指定ModelBinder
:
public string Get([FromQuery][ModelBinder(BinderType = typeof(IntArrayModelBinder))] int[] values)
而官方提供的ByteArrayModelBinder
不需要指定ModelBinder
即可生效:
public string Get([FromQuery]byte[] values)
那么,它是如何做到的呢?
ByteArrayModelBinderProvider
在源码中查找ByteArrayModelBinder
的所有引用。发现只有一处使用:
public class ByteArrayModelBinderProvider : IModelBinderProvider
{
/// <inheritdoc />
public IModelBinder? GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(byte[]))
{
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
return new ByteArrayModelBinder(loggerFactory);
}
return null;
}
}
MvcCoreMvcOptionsSetup
继续查找ByteArrayModelBinderProvider
的所有引用。发现也只有一处使用:
internal class MvcCoreMvcOptionsSetup : IConfigureOptions<MvcOptions>, IPostConfigureOptions<MvcOptions>
{
public void Configure(MvcOptions options)
{
...
options.ModelBinderProviders.Add(new ByteArrayModelBinderProvider());
...
}
}
那么,现在的思路就是,实现IntArrayModelBinderProvider
,然后调用options.ModelBinderProviders.Add(new IntArrayModelBinderProvider());
。
现在,关键就在于这个MvcOptions
在哪访问?
AddControllers 方法
继续查找MvcOptions
的所有引用。发现使用的地方不少,但是,其中有一个扩展方法:
public static IMvcBuilder AddControllers(this IServiceCollection services, Action<MvcOptions>? configure)
而IServiceCollection
是可以在 Startup.cs 中访问的:
public void ConfigureServices(IServiceCollection services)
实现
接下来就好办了。
-
实现 IntArrayModelBinderProvider
:
public class IntArrayModelBinderProvider : IModelBinderProvider
{
public IModelBinder? GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(int[]))
{
return new IntArrayModelBinder();
}
return null;
}
}
-
修改 Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.ModelBinderProviders.Insert(0, new IntArrayModelBinderProvider());
});
}
-
测试一下,执行成功:
[HttpGet]
public string Get([FromQuery]int[] values)
{
return string.Join(" ", values.Select(p => p.ToString()));
}
结论
通过IntArrayModelBinderProvider
,我们无需显示指定ModelBinder
。即可让 ASP.NET Core 自动使用IntArrayModelBinder
。