【问题标题】:String Trim Model Binder in ASP .NET Core 2ASP .NET Core 2 中的字符串修剪模型绑定器
【发布时间】:2018-12-28 05:14:35
【问题描述】:

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

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

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

我很好奇是否有人遇到过与我相同的问题并可能找到解决方案。

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

【问题讨论】:

  • 你是如何配置活页夹的?请发布一些代码。
  • 我没有发布任何示例代码,因为它与引用的文章几乎完全相同。
  • 如果它不是几乎完全相同并且包含一个明显的问题,那么有人应该如何向您指出这一点?不要发布链接,展示你的作品。

标签: asp.net-core asp.net-core-2.0 asp.net-core-webapi


【解决方案1】:

我会在这里加上我的 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);
            }
        }
    }
}

要使用它,要么注册为全局过滤器,要么用 TrimInputStrings 属性装饰你的动作。

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

【讨论】:

  • 好主意。这种方法的一个缺点是它不会像 Model Binder 那样影响 TryUpdateModelAsync 的使用。仅供任何考虑使用的人参考。
  • 效果很好。在我的 .NET Framework 4.7.2 版中,我必须重写 void OnActionExecuting(HttpActionContext actionContext) 才能使其工作。
【解决方案2】:

TrimmingModelBinder 本质上只为字符串配置,如果失败或配置了其他绑定器,则默认返回SimpleTypeModelBinder。因此,如果您的实现与TrimmingModelBinder 中的实现基本相同,那么它肯定只适用于字符串。

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

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

【讨论】:

  • 我们需要ComplexTypeModelBinder吗? SimpleTypeModelBinder不是在complex里面用的吗?这只是一个猜测。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-21
  • 1970-01-01
  • 2019-10-03
  • 2020-11-16
  • 2020-08-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多