ComplexTypeModelBinder在 .Net 5.0 中已被弃用,而它的对应项ComplexObjectModelBinder是sealed的,因此您不能从中扩展。
但是,您可以绕过这个问题。ComplexObjectModelBinderProvider是公开的,您可以使用它来创建一个ComplexObjectModelBinder
。因此,如果您自己制作一个自定义的IModelBinderProvider,您可以使构造函数接受一个ComplexObjectModelBinderProvider
参数,并利用它来创建一个ComplexObjectModelBinder
。然后,您可以将其传递给您的自定义IModelBinder,在执行自定义工作之前,它会愉快地退回到您提供的ComplexObjectModelBinder
。
这里有一个例子。首先,是您的IModelBinder
。如果需要的话,您可以使用DI。(在此示例中,假设我们需要一个DbContext。)
public class MyCustomModelBinder : IModelBinder
{
private readonly IModelBinder _defaultBinder;
private readonly DbContext _dbContext;
public MyCustomModelBinder(IModelBinder defaultBinder, DbContext dbContext)
{
_defaultBinder = defaultBinder;
_dbContext = dbContext;
}
public override Task BindModelAsync(ModelBindingContext bindingContext)
{
return _defaultBinder.BindModelAsync(bindingContext);
}
}
然而,为了在自定义模型绑定器上使用DI,您需要一个帮助类。问题是,当调用 IModelBinderProvider
时,它将无法访问典型请求中的所有服务,例如您的 DbContext。但是,这个类可以帮助解决问题:
internal class DIModelBinder : IModelBinder
{
private readonly IModelBinder _rootBinder;
private readonly ObjectFactory _factory;
public DIModelBinder(Type binderType, IModelBinder rootBinder)
{
if (!typeof(IModelBinder).IsAssignableFrom(binderType))
{
throw new ArgumentException($"Your binderType must derive from IModelBinder.");
}
_factory = ActivatorUtilities.CreateFactory(binderType, new[] { typeof(IModelBinder) });
_rootBinder = rootBinder;
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var requestServices = bindingContext.HttpContext.RequestServices;
var binder = (IModelBinder)_factory(requestServices, new[] { _rootBinder });
return binder.BindModelAsync(bindingContext);
}
}
现在,你已经准备好编写自定义的
IModelBinderProvider
了:
public class MyCustomModelBinderProvider : IModelBinderProvider
{
private readonly IModelBinderProvider _rootProvider;
public MyCustomModelBinderProvider(IModelBinderProvider rootProvider)
{
_rootProvider = rootProvider;
}
public IModelBinder? GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType == typeof(MyModel))
{
var rootBinder = _rootProvider.GetBinder(context)
?? throw new InvalidOperationException($"Root {_rootProvider.GetType()} did not provide an IModelBinder for MyModel.");
return new DIModelBinder(typeof(MyCustomModelBinder), rootBinder);
}
return null;
}
}
最后,在您配置服务的启动文件中,您可以获取ComplexObjectModelBinderProvider
实例,使用它来创建一个新的MyCustomModelBinderProvider
实例,并将其插入到ModelBinderProviders
中。
services.AddMvc(options =>
{
var fallbackProvider = options.ModelBinderProviders
.First(p => p is ComplexObjectModelBinderProvider);
var myProvider = new MyCustomModelBinderProvider(fallbackProvider);
options.ModelBinderProviders.Insert(0, myProvider);
})