使用模型绑定器可以将 NULL 复杂类型传递到控制器端点。
该解决方案并不适用于所有控制器端点,重建模型也不是直截了当的。
在 ASP.NET Core 中传递 NULL 复杂类型参数是否有更好的解决方案?
此功能使用 .NET Standard 按预期工作(允许 NULL),无需任何修改。
使用以下
IModelBinder
和 IModelBinderProvider
:
public class NullModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (context.Metadata.ModelType == typeof(BreakSize))
{
return new BinderTypeModelBinder(typeof(NullModelBinder));
}
return null;
}
}
public class NullModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
throw new ArgumentNullException("bindingContext");
// If null than pass null to the controller - this works
if (bindingContext.HttpContext.Request.Form.ContainsKey(bindingContext.FieldName) && string.IsNullOrEmpty(bindingContext.HttpContext.Request.Form[bindingContext.FieldName]))
bindingContext.Result = ModelBindingResult.Success(null);
else
bindingContext.Result = ModelBindingResult.Success(new BreakSize()); // Todo set values for BreakSize from the form
return Task.CompletedTask;
}
}
假设您的控制器操作如下所示:
public void Endpoint(BreakSize size) { /**/ }
ASP.NET Core 默认执行验证,即它会检查 null 并抛出 400。如果你想允许 null,你需要使用将其标记为 nullable:
public void Endpoint(BreakSize? size) { /**/ }
或
public void Endpoint([MaybeNull] BreakSize size) { /**/ }
使用 Nullable 或 T? 使这些复杂类型参数可选。这允许空值通过而无需模型绑定器手术。 示例:
public IActionResult MyAction([FromBody] BreakSize? breakSize)
{
// Handle null or non-null breakSize like a boss
}
对于那些可选的数据忍者,考虑查询参数而不是正文参数。他们自然地拥抱空值。 示例:
public IActionResult MyAction([FromQuery] BreakSize breakSize)
{
// Null or not, you got this
}
创建自定义模型绑定器以显式处理空值,从而使您能够对绑定过程进行精细控制。 示例:
public class BreakSizeModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
// Implement logic to handle null values and bind properties from request
}
}
使用操作过滤器在请求到达操作方法之前拦截请求并修改模型。非常适合自定义空值处理和其他预处理恶作剧。 示例:
public class NullBreakSizeFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
// Check for null BreakSize parameter and handle it
}
}
利用值提供程序进行声明性空值处理,通过依赖注入提供灵活性。 示例:
public IActionResult MyAction([FromServices] IValueProvider<BreakSize> valueProvider)
{
BreakSize breakSize = valueProvider.GetValue(bindingContext);
// Handle null or non-null breakSize
}
空值的频率:如果空值很常见,可选参数或查询参数可能会更简单。 所需的控制级别:自定义模型绑定或操作过滤器提供更精细的控制。 依赖注入:价值提供者可以作为服务注入以获得更大的灵活性。 可读性和可维护性:选择一种对未来开发人员来说清晰且易于理解的方法。