ASP .NET Core 2 中的字符串修剪模型绑定器

Seb*_*bbo 3 asp.net-core asp.net-core-webapi asp.net-core-2.0

我正在开发一个 .NET Core 2 API 项目,并且一直在尝试实现一个通用字符串修剪模型绑定器,它可以修剪提供的请求参数和字段值的所有字符串值。到目前为止,我的结果喜忧参半,并且正在努力寻找可以为我指明正确方向的工作示例。我一直在尝试实现与Vikash Kumar 发布的相同的模型绑定器。

此模型绑定器适用于通过直接参数传递到控制器操作的所有字符串值,例如public IActionResult Profile(string username),但对于复杂对象中的字符串字段,永远不会调用类的BindModelAsync方法TrimmingModelBinder。我的控制器中 HttpPost 操作的一个示例是public IActionResult Profile([FormBody] ProfileLookupModel model). 模型绑定器似乎不会检查复杂模型的字段。它也不适用于作为字符串列表的字段。

我记得在 .NET Core 之前,指定字符串修剪模型绑定器将递归检查复杂模型的每个字段,甚至是复杂模型中的模型。在 .NET Core 中似乎并非如此,但我可能错了。我的项目是针对netcoreapp2.0框架的。

我很好奇是否有人和我有同样的问题并可能找到了解决方案。

注意:我没有发布任何示例代码,因为它与参考文章中的代码相同。

小智 6

我会在这里加上我的 2 美分。我没有使用某种模型绑定钩子,而是使用了一个动作过滤器。优点之一是开发人员可以选择要使用的操作,而不是对所有请求和模型绑定进行这种处理(并不是说它应该对性能产生太大影响)。顺便说一句,动作过滤器也可以全局应用。

这是我的代码,首先创建一个动作过滤器。

public class TrimInputStringsAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        foreach (var arg in context.ActionArguments.ToList())
        {
            if (arg.Value is string)
            {
                if (arg.Value == null) 
                { 
                    continue; 
                }

                string val = arg.Value as string;
                if (!string.IsNullOrEmpty(val))
                {
                    context.ActionArguments[arg.Key] = val.Trim();
                }

                continue;
            }

            Type argType = arg.Value.GetType();
            if (!argType.IsClass)
            {
                continue;
            }

            TrimAllStringsInObject(arg.Value, argType);
        }
    }

    private void TrimAllStringsInObject(object arg, Type argType)
    {
        var stringProperties = argType.GetProperties()
                                      .Where(p => p.PropertyType == typeof(string));

        foreach (var stringProperty in stringProperties)
        {
            string currentValue = stringProperty.GetValue(arg, null) as string;
            if (!string.IsNullOrEmpty(currentValue))
            {
                stringProperty.SetValue(arg, currentValue.Trim(), null);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

要使用它,请注册为全局过滤器或使用 TrimInputStrings 属性装饰您的操作。

[TrimInputStrings]
public IActionResult Register(RegisterViewModel registerModel)
{
    // Some business logic...
    return Ok();
}
Run Code Online (Sandbox Code Playgroud)


小智 2

TrimmingModelBinderSimpleTypeModelBinder本质上仅针对字符串进行配置,如果失败或配置了其他绑定程序,则默认返回到。因此,如果您的实现本质上与中相同,TrimmingModelBinder那么它肯定只适用于字符串。

对于复杂类型,我建议创建一个新的绑定器及其相应的提供程序,它必须检查模型类型中的所有字符串属性并在绑定之前修剪值。然后在索引 0 处注册此绑定器,以便在尝试任何其他绑定器之前检查第一个绑定器。

services.AddMvc(options => option.ModelBinderProviders.Insert(0, new MyComplexTypeModelBinderProvider());