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

时间:2019-01-22 12:33:54

标签: c# asp.net-core asp.net-core-2.0

我想增强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;}
}

已编辑:
它看起来与this类似,但是如果不是其他的话,那就是ASP.NET Core,并且在链接上也只是ASP.NET。方法,属性,接口...都不相同。

我应该说,如果JSON大小写规则可以工作,那就太好了

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

如果{order: 1, title: "test"}(注意小写)是从JavaScript发送的,则应该起作用。

3 个答案:

答案 0 :(得分:1)

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

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

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

答案 1 :(得分:0)

您可以在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;
    }
}

UpperCase期间,属性值将转换为Model Binding。我已经检查过它,并且效果很好。

答案 2 :(得分:0)

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

第一个属性:

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

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

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

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

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

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());
    }
}

等等!