7

Using the following DataAnnotations in ASP.NET Core 1.1. It would be good to have the max length of the input in my MVC View to be set to restrict the users input.

Model

[Display(Name = "Post Code")]
[MaxLength(8, ErrorMessage = "Maximum number of characters that can be entered is 8!")]
public string PostCode
{ get; set; }

View

<label asp-for="PostCode"></label>
<input style="font-weight: normal;" class="form-control" placeholder="Post Code" asp-for="PostCode" data-val="true" autofocus />

renders as

<input style="font-weight: normal;" class="form-control valid" placeholder="Post Code" data-val="true" autofocus="" type="text" data-val-maxlength="Maximum number of characters that can be entered is 8!" data-val-maxlength-max="8" id="PostCode" name="PostCode" value="" wtx-context="FA5749C8-68AC-44FE-88B9-4BBDF9D48DAE" aria-invalid="false" aria-describedby="PostCode-error">

I am wanting to generate the maxlength attribute from my class data annotation as per the below. (scroll to end);

<input style="font-weight: normal;" class="form-control valid" placeholder="Post Code" data-val="true" autofocus="" type="text" data-val-maxlength="Maximum number of characters that can be entered is 8!" data-val-maxlength-max="8" id="PostCode" name="PostCode" value="" wtx-context="FA5749C8-68AC-44FE-88B9-4BBDF9D48DAE" aria-invalid="false" aria-describedby="PostCode-error" maxlength="8">

Appreciate any advice.

Tseng
  • 61,549
  • 15
  • 193
  • 205
Jason Clark
  • 137
  • 1
  • 2
  • 10
  • For all that's holy, please stop using ".NET Core" when you mean "ASP.NET Core". .NET Core is a runtime and ASP.NET Core is a webstack which runs on top of .NET Core **OR the full .NET Framework** – Tseng Apr 18 '17 at 18:59
  • If the max-length attribute gets set you won't even need to set a data-val-maxlength error message since it won't be possible for the user to exceed the max length. :-) – RonC Apr 19 '17 at 12:29

1 Answers1

10

You may need to implement this functionality via a TagHelper which can read this attribute and add it to the element when rendered, as the default asp-for one won't handle this.

Extending the Input TagHelper

Try declaring a TagHelper as follows within your project, which will etend the existing asp-for helper and handle reading any existing attributes / metadata and appending the necessary attributes to the element:

namespace YourProject.TagHelpers
{
    [HtmlTargetElement("input", Attributes = "asp-for")]
    public class MaxLengthTagHelper : TagHelper
    {
        public override int Order { get; } = 999;

        [HtmlAttributeName("asp-for")]
        public ModelExpression For { get; set; }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            base.Process(context, output);

            // Process only if 'maxlength' attr is not present
            if (context.AllAttributes["maxlength"] == null) 
            {
                // Attempt to check for a MaxLength annotation
                var maxLength = GetMaxLength(For.ModelExplorer.Metadata.ValidatorMetadata);
                if (maxLength > 0)
                {
                    output.Attributes.Add("maxlength", maxLength);
                }
            }
        }

        private static int GetMaxLength(IReadOnlyList<object> validatorMetadata)
        {
            for (var i = 0; i < validatorMetadata.Count; i++)
            {
                var stringLengthAttribute = validatorMetadata[i] as StringLengthAttribute;
                if (stringLengthAttribute != null && stringLengthAttribute.MaximumLength > 0)
                {
                    return stringLengthAttribute.MaximumLength;
                }

                var maxLengthAttribute = validatorMetadata[i] as MaxLengthAttribute;
                if (maxLengthAttribute != null && maxLengthAttribute.Length > 0)
                {
                    return maxLengthAttribute.Length;
                }
            }
            return 0;
        }
    }
}

Using The TagHelper

Then add a reference to it, either directly in your specific view, or globally in the _ViewImports.cshtml file as seen below:

@using YourProject
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, YourProject

Once added, this extended TagHelper should automatically decorate your element with the appropriate maxlength attribute, if present on your property:

<!-- Input -->
<label asp-for="PostCode"></label>
<input style="font-weight: normal;" class="form-control" placeholder="Post Code" asp-for="PostCode" data-val="true" autofocus />

<!-- Rendered -->
<label for="PostCode">Post Code</label>
<input style="font-weight: normal;" class="form-control" placeholder="Post Code" data-val="true" autofocus="" type="text" data-val-maxlength="Maximum number of characters that can be entered is 8!" data-val-maxlength-max="8" id="PostCode" name="PostCode" value="" maxlength="8">
Rion Williams
  • 74,820
  • 37
  • 200
  • 327
  • Perfect - Worked a charm - Thanks Rion! – Jason Clark Apr 21 '17 at 15:17
  • This is great, as it already considers the maxLength and stringLength attributes. I extended this TagHelper with the validation of the minLength attribute and the maxLength resulting from possible range attribute settings (i.e. Range(2000,2099) => maxLength = 4) and use it as CustomInputTagHelper. – Marc_Sei Sep 08 '20 at 14:05