首页 文章详情

如何让 ASP.NET Core 支持绑定查询字符串中的数组(2)

DotNet NB | 96 2022-06-01 14:28 0 0 0
UniSMS (合一短信)

前言

上回说到,我们实现了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)

实现

接下来就好办了。

  1. 实现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;
    }
}
  1. 修改 Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        options.ModelBinderProviders.Insert(0, new IntArrayModelBinderProvider());
    });
}
  1. 测试一下,执行成功:
[HttpGet]
public string Get([FromQuery]int[] values)
{
    return string.Join(" ", values.Select(p => p.ToString()));
}

结论

通过IntArrayModelBinderProvider,我们无需显示指定ModelBinder。即可让 ASP.NET Core 自动使用IntArrayModelBinder


推荐阅读:
  API 工程化分享
  我的微软 MVP 之路
【译】ASP.NET Core 6 中的性能改进
【译】.NET 7 预览版 1 中的 ASP.NET Core 更新
【译】C# 11 特性的早期预览

点击下方卡片关注DotNet NB

一起交流学习

▲ 点击上方卡片关注DotNet NB,一起交流学习

请在公众号后台

回复 【路线图】获取.NET 2021开发者路线图
回复 【原创内容】获取公众号原创内容
回复 【峰会视频】获取.NET Conf开发者大会视频
回复 【个人简介】获取作者个人简介
回复 【年终总结】获取作者年终总结
回复 加群加入DotNet NB 交流学习群

长按识别下方二维码,或点击阅读原文。和我一起,交流学习,分享心得。


good-icon 0
favorite-icon 0
收藏
回复数量: 0
    暂无评论~~
    Ctrl+Enter