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

asp.net core custom model binding
asp.net core model binding example
asp net core model binding complex object
defaultmodelbinder
asp net core model binding list of objects
asp.net core polymorphic model binding
web api custom model binder
model binding in mvc c# corner

I would like to enhance final result that ModelBinder returns. For example:

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

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

In API method I expect that all string properties in MyModel which has MyUpperCaseAttribute is in upper case.

For example:

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

My idea was to override default ModelBinder and enumerate through all properties and check if property is string and has MyUpperCaseAttribute and correct property value to upper case. I check documentation, but doesn't examples doesn't fill right, since they completely redesign what is returned. I would like to just modify result properties.

What would be the best option to achieve desired behaviour?

Important: (edited): It would be nice if directive attributes could be stacked:

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

Edited: It looks similar to this, but if not other, this is ASP.NET Core, and on link is just ASP.NET. Method, properties, interfaces... are not the same.

I should say, that it would be nice if JSON case rule would work:

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

should work if {order: 1, title: "test"} (notice lowercase) is send from JavaScript.


This might not be the 'best' option, but I would just use .ToUpper() extension method instead of a custom attribute filter.

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

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

Model Binding, ASP.NET MVC framework also enables you to specify which properties of a model class you want to bind. The [Bind] attribute will let you specify the exact  Note. The preceding AuthorEntityBinder class is intended to illustrate a custom model binder. The class isn't intended to illustrate best practices for a lookup scenario. For lookup, bind the authorId and query the database in an action method.


You can do this thing inside your MyUpperCaseAttribute as follows:

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

Property value will be converted to UpperCase during Model Binding. I have checked it in my side and it works perfectly.

Custom Model Binding in ASP.NET Core, You can use a custom model binder to fetch data based on the key. A complex type is converted from multiple input values. ASP.NET Core MVC can take a base64-encoded string and use a As long as the binder can bind request data to appropriately named properties or arguments, model binding  You can extend model binding by writing a custom model binder and using the [ModelBinder] attribute to select it for a given target. Learn more about custom model binding . Manual model binding


There's a big red herring here, and that's the fact that it appears that this is the sort of thing that could and should be accomplished via model binding. Unfortunately, that's not the case in ASP.Net Core Web API: because the incoming data is JSON, it is in fact handled by input formatters, not model binders. Therefore, in order to achieve the desired effect, you need to create your own custom input formatter that replaces the standard JsonInputFormatter.

First the attribute:

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

Then we decorate our model class with it:

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

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

Now create our custom input formatter that checks for that attribute and transforms the output if necessary. In this case, it simply wraps and delegates to JsonInputFormatter to do the heavy lifting as normal, then modifies the result if it finds our ToUppercaseAttribute attribute on any string property:

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

Next we create an extension method that makes it simple to substitute the default JsonInputFormatter with our custom formatter:

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

And finally, call that method to effect the replacement in Startup.cs:

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

Et voilà!

ASP.NET Core 2 Fundamentals: Build cross-platform apps and dynamic , Change the view, as follows: Go to https://goo.gl/ScepWa to access the code. @​model Lesson4.Models.Order <table border="1"> <tr> <th>Product Name</th><th​>Price</th></tr> Model binding can also be enhanced and customized. class contains the Name and EmailID properties, the model binder would not complain​  Before I jump into the solution, I’ll firstly explain at a high level how the model binding flow works in ASP.NET Core MVC. To understand this better I ended up following steps from this blog post where I discuss how we can add the MVC source solution to our code, allowing us to debug into it.


Custom ModelBinding in ASP.NET MVC Core, We use this binder to HTML encode values at bind time. explain at a high level how the model binding flow works in ASP. It attempts to match up values coming in on the request to any properties expected Update the thing in the database here public class HtmlEncodeModelBinder : IModelBinder. To demonstrate a few examples where filters can improve the design of an ASP.NET MVC Core app, I’ve built a simple API that provides basic create, read, update, delete (CRUD) functionality and follows a few standard rules for handling invalid requests.


Model Binding: A Simple Guide to Everything You Need to Know, In an ASP.NET MVC project, the model binder is a feature of the framework that of your model class and maps fields from the HTTP request into the model. So a URL of the form ~/Contact?id=5 will pass a null value for the description parameter. Here's an example of only binding a specified property. Model Binding is a process done by ASP.NET Core MVC to extract data from HTTP requests and provide them to Action method’s arguments. Let us see the first example of Model Binding process in this example project.


Pro Entity Framework Core 2 for ASP.NET Core MVC, Id" /> <button type="submit" class="btn btn-outline-danger"> Delete </button> I have sent just the primary key value, which the MVC model binder will use to create values for properties that are going to be ignored and that will increase the  In the last post about OutputFormatters I wrote about sending data out to the clients in different formats. In this post we are going to do it the other way. This post is about data you get into your Web API from outside. What if you get data in a special format or what if you get data you need to validate in a special way. ModelBinders will help you handling this.