Model normalization before model validation in Asp.Net Core 2.0+

人走茶凉 提交于 2019-12-11 17:40:06

问题


I'm using automatic model validation (see "Better Input Processing") to keep my controllers clean; so:

[HttpPost]
[ProducesResponseType(typeof(Product), 201)]
public IActionResult Post([FromBody] Product product)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    product = _repository.AddProduct(product);
    return CreatedAtAction(nameof(Get), new { id = product.Id }, product);
}

becomes:

[HttpPost]
[ProducesResponseType(201)]
public ActionResult<Product> Post(Product product)
{
    _repository.AddProduct(product);
    return CreatedAtAction(nameof(Get), new { id = product.Id }, product);
}

However, I do have a few models that have a phonenumber property. I would like to 'normalize' these before the model validation is invoked. What I mean is that I want to normalize these properties (of type string) from all kinds of input like:

  • +31 23 456 7890
  • (023) 4567890
  • 023 - 4567 890
  • ...

To E.164 notation:

  • +31234567890

So in whatever form a user enters a phonenumber, before validation is invoked I want to be sure it's always in E.164 form ('normalized'). How this normalization is done is irrelevant (I use libphonenumber if you insist). As a second, maybe less convoluted, example I can imagine a string to be always upper-/lowercased before validation is invoked.

What would be the correct, or best, way to invoke my normalization process before the validation is invoked? Would I have to write some middleware?

Also relevant: my models contain attributes so the normalizer knows which properties to normalize (and how):

class ExampleModel {

    public int Id { get; set; }

    public string Name { get; set; }

    [NormalizedNumber(NumberFormat.E164)]
    public string Phonenumber { get; set; }
}

I guess the middleware(? or whatever the solution is going to be) can then take a model, figure out if any of the properties (recursively) have the attribute and invoke the normalizer if needed.


回答1:


Maybe you can use an approach like this using Formatter. I have used similar approach to convert all incoming dates to UTC format in my API

public class JsonModelFormatter : JsonMediaTypeFormatter
{
    public override System.Threading.Tasks.Task<Object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger, CancellationToken cancellationToken)
    {

        System.Threading.Tasks.Task<Object> baseTask = base.ReadFromStreamAsync(type, readStream, content, formatterLogger, cancellationToken);

        if (baseTask.Result != null)
        {
            var properties = baseTask.Result.GetType().GetProperties();
            foreach (var property in properties)
            {
                //Check Property attribute and decide if you need to format it
                if (property.CustomAttributes.Where (x=> you condition here))
                {
                    if (property.CanWrite && property.GetValue(baseTask.Result, null) != null)
                    {
                        var propValue = ((string)property.GetValue(baseTask.Result, null));
                       //Update propValue here 
                       property.SetValue(baseTask.Result, newPropValue);
                    }
                }
            }

        }
        return baseTask;
    }

    public override bool CanReadType(Type type)
    {
        return true;
    }
}


来源:https://stackoverflow.com/questions/53417355/model-normalization-before-model-validation-in-asp-net-core-2-0

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!