繁体   English   中英

如何在ASP.NET Core中增强ModelBinder(更新模型类的属性值)

[英]How can I enhance ModelBinder in ASP.NET Core (update property values for a model class)

我想增强ModelBinder返回的最终结果。
例如:

public class MyModel
{
    public int Order {get;set;}

    [MyUpperCaseAttribute]
    public string Title {get;set;}
}

在API方法中,我希望MyModel中具有MyUpperCaseAttribute所有字符串属性都是大写的。

例如:

[HttpPost("AddRecord")]
public async Task<ActionResult<int>> AddRecord(MyModel model)
{
    model.Title should be upper case, even if send from client in lower case.
}

我的想法是覆盖默认的ModelBinder并枚举所有属性,并检查属性是否为字符串并且具有MyUpperCaseAttribute并将属性值更正为大写。 我检查文档,但是没有示例没有正确填写,因为它们完全重新设计了返回的内容。 我想修改结果属性。

什么是实现理想行为的最佳选择?

重要:(已编辑):
如果可以堆叠指令属性,那将是很好的:

public class MyModel
{
    public int Order {get;set;}
    [MyUpperCaseAttribute]
    [RemoveSpacesAttribute]
    public string Title {get;set;}
}

编辑:
它看起来与类似,但如果不是其他,则这是ASP.NET Core,而链接上只是ASP.NET。 方法,属性,接口......不一样。

我应该说,如果JSON案例规则可行,那将是很好的:

public class MyModel
{
    public int Order {get;set;}
    public string Title {get;set;}
}

如果从JavaScript发送{order: 1, title: "test"} (通知小写),则应该有效。

这可能不是“最佳”选项,但我只使用.ToUpper()扩展方法而不是自定义属性过滤器。

public class MyModel
{
    private string _title;
    public int Order {get;set;}

    public string Title { get => _title.ToUpper(); set => _title = value.ToUpper(); }
}

您可以在MyUpperCaseAttribute中执行以下操作:

public class MyUpperCaseAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if(value != null)
        {
            validationContext.ObjectType
            .GetProperty(validationContext.MemberName)
            .SetValue(validationContext.ObjectInstance, value.ToString().ToUpper(), null);
        }

        return null;
    }
}

Model Binding期间,属性值将转换为UpperCase 我已经在我身边检查了它,它完美无缺。

这里有一个大红鲱鱼,这就是看起来这是可以而且应该通过模型绑定完成的事情。 不幸的是,在ASP.Net Core Web API中并非如此:因为传入的数据是JSON,它实际上是由输入格式化程序处理的,而不是模型绑定程序。 因此,为了达到预期的效果,您需要创建自己的自定义输入格式化程序来替换标准的JsonInputFormatter

首先是属性:

[AttributeUsage(AttributeTargets.Property)]
public class ToUppercaseAttribute : Attribute
{
}

然后我们用它装饰我们的模型类:

public class MyModel
{
    public int Order { get; set; }

    [ToUppercase]
    public string Title { get; set; }
}

现在创建我们的自定义输入格式化程序,检查该属性并在必要时转换输出。 在这种情况下,它只是包装并委托给JsonInputFormatter来正常执行繁重的操作,然后在任何string属性上找到ToUppercaseAttribute属性时修改结果:

public class ToUppercaseJsonInputFormatter : TextInputFormatter
{
    private readonly JsonInputFormatter _jsonInputFormatter;

    public ToUppercaseJsonInputFormatter(JsonInputFormatter jsonInputFormatter)
    {
        _jsonInputFormatter = jsonInputFormatter;

        foreach (var supportedEncoding in _jsonInputFormatter.SupportedEncodings)
            SupportedEncodings.Add(supportedEncoding);

        foreach (var supportedMediaType in _jsonInputFormatter.SupportedMediaTypes)
           SupportedMediaTypes.Add(supportedMediaType);
    }

    public override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
    {
        var result = _jsonInputFormatter.ReadRequestBodyAsync(context, encoding);

        foreach (var property in context.ModelType.GetProperties().Where(p => p.PropertyType.IsAssignableFrom(typeof(string))
            && p.CustomAttributes.Any(a => a.AttributeType.IsAssignableFrom(typeof(ToUppercaseAttribute)))))
        {
            var value = (string)property.GetValue(result.Result.Model);
            property.SetValue(result.Result.Model, value.ToUpper());
        }

        return result;
    }
}

接下来,我们创建一个扩展方法,使用我们的自定义格式化程序替换默认的JsonInputFormatter变得简单:

public static class MvcOptionsExtensions
{
    public static void UseToUppercaseJsonInputFormatter(this MvcOptions opts)
    {
        if (opts.InputFormatters.FirstOrDefault(f => f is JsonInputFormatter && !(f is JsonPatchInputFormatter)) is JsonInputFormatter jsonInputFormatter)
        {
            var jsonInputFormatterIndex = opts.InputFormatters.IndexOf(jsonInputFormatter);
            opts.InputFormatters[jsonInputFormatterIndex] = new ToUppercaseJsonInputFormatter(jsonInputFormatter);
        }
    }
}

最后,调用该方法来实现Startup.cs的替换:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services
            .AddMvc(options => options.UseToUppercaseJsonInputFormatter());
    }
}

Etvoilà!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM