Search code examples
c#asp.net-mvcasp.net-corerazor-pages

How to trim input text


Issue: How to trim text using asp-for tag & razor page?

Detail: I have a input field where user can enter there firstname. I noticed user can enter multi spaces or tabs. Since I am using asp-for tag, it will auto bind the data to Person object on OnPost() Method

I am trying not to use following methods Request.Form("firstname").trim() or pass value though OnPost(string firstname) Method; Because whole point of asp-for tag is to auto bind your values to object rather than manually getting each values like using name tag.

If there isn't any way to do this, than what is the point of asp.for tag? bc in real world you will end up checking for extra spaces any ways.

<input asp-for="Person.FirstName"  />
<span asp-validation-for="Person.FirstName" class="text-danger"></span>

     [BindProperty]
    public Person_Model Person { get; set; } = default!;
    [BindProperty(SupportsGet = true)]
    public string? FirstName{ get; set; }

    public async Task<IActionResult> OnPostAsync()
    {
        // here First_name can have spaces
        _context2.my_DbSet.Add(Person);
        await _context2.SaveChangesAsync();
    }

public class Person_Model
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Int64 Id { get; set; }

    public string? FirstName{ get; set; }
 }

I tried adding RegularExpression, but this will just give me error if there is whtie space inside text-field. I just want to trim it.

[RegularExpression(@"[^\s]+")]
public string? FirstName{ get; set; }

Solution

  • The recommended method for centralising trimming of input strings is to create a custom model binder which does this as part of the model binding process.

    Create a class called TrimModelBinder:

    public class TrimModelBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            if (valueProviderResult != ValueProviderResult.None)
            {
                bindingContext.Result = ModelBindingResult.Success(valueProviderResult.FirstValue?.Trim());
            }
            return Task.CompletedTask;
        }
    }
    

    Create a ModelBinderProvider that returns your new model binder if the binding target is a string:

    public class TrimModelBinderProvider : IModelBinderProvider
    {
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context.Metadata.ModelType == typeof(string))
            {
                return new BinderTypeModelBinder(typeof(TrimModelBinder));
            }
            return null;
        }
    }
    

    Register this with the services container:

    builder.Services.AddMvc(options => options.ModelBinderProviders.Insert(0, new TrimModelBinderProvider()));
    

    Now you no longer have to call Trim() on every input string.