/// <inheritdoc /> public override void Process(TagHelperContext context, TagHelperOutput output) { ModelExplorer modelExplorer = For.ModelExplorer; IDictionary <string, object>?htmlAttributes = null; // Pass through attributes that are also well-known HTML attributes. // Must be done prior to any copying from a TagBuilder. if (InputTypeName is not null) { output.CopyHtmlAttribute("type", context); } if (Name is not null) { output.CopyHtmlAttribute(nameof(Name), context); } if (Value is not null) { output.CopyHtmlAttribute(nameof(Value), context); } var inputType = string.IsNullOrEmpty(InputTypeName) ? InputType.CheckBox.ToString().ToLowerInvariant() : InputTypeName.ToLowerInvariant(); // inputType may be more specific than default the generator chooses below. if (output.Attributes.ContainsName("type") != true) { output.Attributes.SetAttribute("type", inputType); } // Ensure Generator does not throw due to empty "fullName" if user provided a name attribute. if (string.IsNullOrEmpty(For.Name) && string.IsNullOrEmpty(ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix) && string.IsNullOrEmpty(Name) != true) { htmlAttributes = new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase) { { "name", Name }, }; } TagBuilder tagBuilder = GenerateCheckBox(modelExplorer, htmlAttributes); output.MergeAttributes(tagBuilder); }
/// <inheritdoc /> /// <remarks>Does nothing if <see cref="For"/> is <c>null</c>.</remarks> /// <exception cref="InvalidOperationException"> /// Thrown if <see cref="Format"/> is non-<c>null</c> but <see cref="For"/> is <c>null</c>. /// </exception> public override void Process(TagHelperContext context, TagHelperOutput output) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } // Pass through attributes that are also well-known HTML attributes. Must be done prior to any copying // from a TagBuilder. if (InputTypeName != null) { output.CopyHtmlAttribute("type", context); } if (Value != null) { output.CopyHtmlAttribute(nameof(Value), context); } // Note null or empty For.Name is allowed because TemplateInfo.HtmlFieldPrefix may be sufficient. // IHtmlGenerator will enforce name requirements. var metadata = For.Metadata; var modelExplorer = For.ModelExplorer; if (metadata == null) { throw new InvalidOperationException(Resources.FormatTagHelpers_NoProvidedMetadata( "<input>", ForAttributeName, nameof(IModelMetadataProvider), For.Name)); } string inputType; string inputTypeHint; if (string.IsNullOrEmpty(InputTypeName)) { // Note GetInputType never returns null. inputType = GetInputType(modelExplorer, out inputTypeHint); } else { inputType = InputTypeName.ToLowerInvariant(); inputTypeHint = null; } // inputType may be more specific than default the generator chooses below. if (!output.Attributes.ContainsName("type")) { output.Attributes["type"] = inputType; } TagBuilder tagBuilder; switch (inputType) { case "checkbox": GenerateCheckBox(modelExplorer, output); return; case "hidden": tagBuilder = Generator.GenerateHidden( ViewContext, modelExplorer, For.Name, value: For.Model, useViewData: false, htmlAttributes: null); break; case "password": tagBuilder = Generator.GeneratePassword( ViewContext, modelExplorer, For.Name, value: null, htmlAttributes: null); break; case "radio": tagBuilder = GenerateRadio(modelExplorer); break; default: tagBuilder = GenerateTextBox(modelExplorer, inputTypeHint, inputType); break; } if (tagBuilder != null) { // This TagBuilder contains the one <input/> element of interest. Since this is not the "checkbox" // special-case, output is a self-closing element no longer guaranteed. output.MergeAttributes(tagBuilder); output.Content.Append(tagBuilder.InnerHtml); } }
/// <inheritdoc /> /// <remarks>Does nothing if <see cref="For"/> is <c>null</c>.</remarks> /// <exception cref="InvalidOperationException"> /// Thrown if <see cref="Format"/> is non-<c>null</c> but <see cref="For"/> is <c>null</c>. /// </exception> public override void Process(TagHelperContext context, TagHelperOutput output) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } // Pass through attributes that are also well-known HTML attributes. Must be done prior to any copying // from a TagBuilder. if (InputTypeName != null) { output.CopyHtmlAttribute("type", context); } if (Name != null) { output.CopyHtmlAttribute(nameof(Name), context); } if (Value != null) { output.CopyHtmlAttribute(nameof(Value), context); } // Note null or empty For.Name is allowed because TemplateInfo.HtmlFieldPrefix may be sufficient. // IHtmlGenerator will enforce name requirements. var metadata = For.Metadata; var modelExplorer = For.ModelExplorer; if (metadata == null) { throw new InvalidOperationException(Resources.FormatTagHelpers_NoProvidedMetadata( "<input>", ForAttributeName, nameof(IModelMetadataProvider), For.Name)); } string inputType; string inputTypeHint; if (string.IsNullOrEmpty(InputTypeName)) { // Note GetInputType never returns null. inputType = GetInputType(modelExplorer, out inputTypeHint); } else { inputType = InputTypeName.ToLowerInvariant(); inputTypeHint = null; } // inputType may be more specific than default the generator chooses below. if (!output.Attributes.ContainsName("type")) { output.Attributes.SetAttribute("type", inputType); } // Ensure Generator does not throw due to empty "fullName" if user provided a name attribute. IDictionary <string, object> htmlAttributes = null; if (string.IsNullOrEmpty(For.Name) && string.IsNullOrEmpty(ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix) && !string.IsNullOrEmpty(Name)) { htmlAttributes = new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase) { { "name", Name }, }; } TagBuilder tagBuilder; switch (inputType) { case "hidden": tagBuilder = GenerateHidden(modelExplorer, htmlAttributes); break; case "checkbox": tagBuilder = GenerateCheckBox(modelExplorer, output, htmlAttributes); break; case "password": tagBuilder = Generator.GeneratePassword( ViewContext, modelExplorer, For.Name, value: null, htmlAttributes: htmlAttributes); break; case "radio": tagBuilder = GenerateRadio(modelExplorer, htmlAttributes); break; default: tagBuilder = GenerateTextBox(modelExplorer, inputTypeHint, inputType, htmlAttributes); break; } if (tagBuilder != null) { // This TagBuilder contains the one <input/> element of interest. output.MergeAttributes(tagBuilder); if (tagBuilder.HasInnerHtml) { // Since this is not the "checkbox" special-case, no guarantee that output is a self-closing // element. A later tag helper targeting this element may change output.TagMode. output.Content.AppendHtml(tagBuilder.InnerHtml); } } }
/// <summary> /// Synchronously executes the <see /// cref="T:Microsoft.AspNetCore.Razor.TagHelpers.TagHelper"/> with the given <paramref /// name="context"/> and <paramref name="output"/>. /// </summary> /// <param name="context">Contains information associated with the current HTML tag.</param> /// <param name="output">A stateful HTML element used to generate an HTML tag.</param> /// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.InvalidOperationException"></exception> public override void Process(TagHelperContext context, TagHelperOutput output) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } if (ForAttribute == null) { return; } if (InputTypeName != null) { output.CopyHtmlAttribute("type", context); } if (Value != null) { output.CopyHtmlAttribute(nameof(Value), context); } var metadata = ForAttribute.Metadata; var modelExplorer = ForAttribute.ModelExplorer; if (metadata == null) { throw new InvalidOperationException( string.Format("The {2} was unable to provide metadata about '{1}' expression value '{3}' for {0}.", "<input>", "qf-for", nameof(IModelMetadataProvider), ForAttribute.Name)); } string inputType; string inputTypeHint; if (string.IsNullOrEmpty(InputTypeName)) { inputType = GetInputType(modelExplorer, out inputTypeHint); } else { inputType = InputTypeName.ToLowerInvariant(); inputTypeHint = null; } var format = string.IsNullOrEmpty(Format) ? GetFormat(modelExplorer, inputTypeHint, inputType) : Format; if (format == "checkbox") { GenerateCheckBox(modelExplorer, output, ForAttribute); } else { var val = string.IsNullOrEmpty(Value) ? ForAttribute.Model : Value; if (modelExplorer.ModelType == typeof(DateTime) || modelExplorer.ModelType == typeof(DateTimeOffset)) { DateTime convertedValue = default(DateTime); DateTime.TryParse(val.ToString(), out convertedValue); if (convertedValue == default(DateTime)) { return; } } var formattedVal = string.IsNullOrEmpty(format) ? Convert.ToString(val, CultureInfo.CurrentCulture) : string.Format(format, val); output.PostContent.AppendHtml(formattedVal); } }
/// <inheritdoc/> public override void Process(TagHelperContext context, TagHelperOutput output) { // Pass through attributes that are also well-known HTML attributes. Must be done prior to any copying // from a TagBuilder. if (InputTypeName != null) { output.CopyHtmlAttribute("type", context); } if (Value != null) { output.CopyHtmlAttribute(nameof(Value), context); } string inputType; string inputTypeHint; if (string.IsNullOrEmpty(InputTypeName)) { // Note GetInputType never returns null. inputType = GetInputType(Column, out inputTypeHint); } else { inputType = InputTypeName.ToLowerInvariant(); inputTypeHint = null; } // inputType may be more specific than default the generator chooses below. if (!output.Attributes.ContainsName("type")) { output.Attributes.SetAttribute("type", inputType); } TagBuilder tagBuilder; switch (inputType) { case "hidden": tagBuilder = GenerateHidden(); break; case "checkbox": tagBuilder = GenerateCheckBox(output); break; case "password": tagBuilder = Generator.GeneratePassword(ViewContext, FullHtmlFieldName, Column, value: null, htmlAttributes: null); break; case "radio": tagBuilder = GenerateRadio(); break; default: tagBuilder = GenerateTextBox(inputTypeHint, inputType); break; } if (tagBuilder != null) { // This TagBuilder contains the one <input/> element of interest. output.MergeAttributes(tagBuilder); if (tagBuilder.HasInnerHtml) { // Since this is not the "checkbox" special-case, no guarantee that output is a self-closing // element. A later tag helper targeting this element may change output.TagMode. output.Content.AppendHtml(tagBuilder.InnerHtml); } } }
/// <inheritdoc /> /// <remarks>Does nothing if <see cref="For"/> is <c>null</c>.</remarks> /// <exception cref="InvalidOperationException"> /// Thrown if <see cref="Format"/> is non-<c>null</c> but <see cref="For"/> is <c>null</c>. /// </exception> public override void Process(TagHelperContext context, TagHelperOutput output) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } var validations = output.Attributes.Where(x => x.Name.ToString().Contains("data-val-")).ToArray(); if (LanguageSupport && validations.Any()) { foreach (var validation in validations) { output.Attributes.RemoveAll(validation.Name); string message = validation.Value.ToString(); output.Attributes.Add(validation.Name, languageProviderService.GetlangByKey(message)); } } // Pass through attributes that are also well-known HTML attributes. Must be done prior to any copying // from a TagBuilder. if (InputTypeName != null) { output.CopyHtmlAttribute("type", context); } if (Value != null) { output.CopyHtmlAttribute(nameof(Value), context); } // Note null or empty For.Name is allowed because TemplateInfo.HtmlFieldPrefix may be sufficient. // IHtmlGenerator will enforce name requirements. ModelMetadata metadata = For.Metadata; ModelExplorer modelExplorer = For.ModelExplorer; if (metadata == null) { return; } string inputType; string inputTypeHint; if (string.IsNullOrEmpty(InputTypeName)) { // Note GetInputType never returns null. inputType = GetInputType(modelExplorer, out inputTypeHint); } else { inputType = InputTypeName.ToLowerInvariant(); inputTypeHint = null; } // inputType may be more specific than default the generator chooses below. if (!output.Attributes.ContainsName("type")) { output.Attributes.SetAttribute("type", inputType); } TagBuilder tagBuilder; switch (inputType) { case "hidden": tagBuilder = GenerateHidden(modelExplorer); break; case "checkbox": GenerateCheckBox(modelExplorer, output); return; case "password": tagBuilder = Generator.GeneratePassword( ViewContext, modelExplorer, For.Name, value: null, htmlAttributes: null); break; case "radio": tagBuilder = GenerateRadio(modelExplorer); break; default: tagBuilder = GenerateTextBox(modelExplorer, inputTypeHint, inputType); break; } if (tagBuilder != null) { // This TagBuilder contains the one <input/> element of interest. output.MergeAttributes(tagBuilder); if (tagBuilder.HasInnerHtml) { // Since this is not the "checkbox" special-case, no guarantee that output is a self-closing // element. A later tag helper targeting this element may change output.TagMode. output.Content.AppendHtml(tagBuilder.InnerHtml); } } }
/// <inheritdoc /> /// <remarks>Does nothing if <see cref="For"/> is <c>null</c></remarks> public override void Process(TagHelperContext context, TagHelperOutput output) { // Pass through attributes that are also well-known HTML attributes. Must be done prior to any copying // from a TagBuilder. if (!string.IsNullOrEmpty(InputTypeName)) { output.CopyHtmlAttribute("type", context); } if (Value != null) { output.CopyHtmlAttribute(nameof(Value), context); } if (For == null) { // Regular HTML <input/> element. Just make sure Format wasn't specified. if (Format != null) { throw new InvalidOperationException(Resources.FormatInputTagHelper_UnableToFormat( "<input>", nameof(For).ToLowerInvariant(), nameof(Format).ToLowerInvariant())); } } else { // Note null or empty For.Name is allowed because TemplateInfo.HtmlFieldPrefix may be sufficient. // IHtmlGenerator will enforce name requirements. var metadata = For.Metadata; if (metadata == null) { throw new InvalidOperationException(Resources.FormatTagHelpers_NoProvidedMetadata( "<input>", nameof(For).ToLowerInvariant(), nameof(IModelMetadataProvider), For.Name)); } string inputType; string inputTypeHint; if (string.IsNullOrEmpty(InputTypeName)) { inputType = GetInputType(metadata, out inputTypeHint); } else { inputType = InputTypeName.ToLowerInvariant(); inputTypeHint = null; } if (!string.IsNullOrEmpty(inputType)) { // inputType may be more specific than default the generator chooses below. // TODO: Use Attributes.ContainsKey once aspnet/Razor#186 is fixed. if (!output.Attributes.Any( item => string.Equals("type", item.Key, StringComparison.OrdinalIgnoreCase))) { output.Attributes["type"] = inputType; } } TagBuilder tagBuilder; switch (inputType) { case "checkbox": GenerateCheckBox(metadata, output); return; case "hidden": tagBuilder = Generator.GenerateHidden( ViewContext, metadata, For.Name, value: metadata.Model, useViewData: false, htmlAttributes: null); break; case "password": tagBuilder = Generator.GeneratePassword( ViewContext, metadata, For.Name, value: null, htmlAttributes: null); break; case "radio": tagBuilder = GenerateRadio(metadata); break; default: tagBuilder = GenerateTextBox(metadata, inputTypeHint, inputType); break; } if (tagBuilder != null) { // This TagBuilder contains the one <input/> element of interest. Since this is not the "checkbox" // special-case, output is a self-closing element and can merge the TagBuilder in directly. output.SelfClosing = true; output.Merge(tagBuilder); } } }
public InputModelInfo( IHtmlGenerator generator, ModelExpression forModelExp, string format, string inputTypeName, // <- [HtmlAttributeName("type")] string value, string placeholder, string labelText, ViewContext viewContext) : base(generator) { base.For = forModelExp; base.Format = format; base.InputTypeName = inputTypeName; base.Value = value; base.ViewContext = viewContext; HtmlFieldPrefix = ViewContext?.ViewData?.TemplateInfo?.HtmlFieldPrefix; Name = For.Name; FullName = ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(Name); PropertyName = Meta.PropertyName; FullNameId = TagBuilder.CreateSanitizedId(FullName, "_"); if (placeholder.NotNulle()) { Placeholder = placeholder.HtmlEncode(undoApostropheEsc: true); // important for placeholder } LabelText = labelText.NotNulle() && labelText.IsNullOrWhiteSpace() ? " " : labelText.FirstNotNulle(GetLabelText()).HtmlEncode(); // THIS allows them to send in " " (space) if they want no label, but we can't treat empty as that, // because e.g. label="" sends in empty not null, but what about label="@Model.Prop", want to allow // a default to fall back if default is not set if (InputTypeName.IsNulle()) { InputTypeName = GetInputType(For.ModelExplorer, out string inputTypeHint); // Note GetInputType never returns null. // Nick's note: If none defaults to "text", so do NOT set that default yourself anywhere else, this will handle InputTypeHint = inputTypeHint; } else { InputTypeName = InputTypeName.ToLowerInvariant(); InputTypeHint = null; } if (For.Metadata == null) { ThrowExOnMetadataNull(ForAttributeName, Name); } if (Format.IsNulle()) { Format = GetFormat(For.ModelExplorer, InputTypeHint, InputTypeName); } Type t = ModelType = this.ModelExplorer?.ModelType; if (t != null) { if (!t.IsPrimitive) { NullableBaseType = t.GetUnderlyingTypeIfNullable(); } t = MainType; TypeAllowsStringBasedEqualityComparison = t.IsPrimitive || t.IsEnum || ExtraPrimitiveTypesAllowingStringBasedEqualityChecks.ContainsKey(t); } }
/// <inheritdoc /> /// <remarks>Does nothing if <see cref="For"/> is <c>null</c>.</remarks> /// <exception cref="InvalidOperationException"> /// Thrown if <see cref="Format"/> is non-<c>null</c> but <see cref="For"/> is <c>null</c>. /// </exception> public override void Process(TagHelperContext context, TagHelperOutput output) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } // Pass through attributes that are also well-known HTML attributes. Must be done prior to any copying // from a TagBuilder. if (InputTypeName != null) { output.CopyHtmlAttribute("type", context); } if (Value != null) { output.CopyHtmlAttribute(nameof(Value), context); } // Note null or empty For.Name is allowed because TemplateInfo.HtmlFieldPrefix may be sufficient. // IHtmlGenerator will enforce name requirements. var metadata = For.Metadata; var modelExplorer = For.ModelExplorer; if (metadata == null) { throw new InvalidOperationException(); } string inputType; string inputTypeHint; if (string.IsNullOrEmpty(InputTypeName)) { // Note GetInputType never returns null. inputType = GetInputType(modelExplorer, out inputTypeHint); } else { inputType = InputTypeName.ToLowerInvariant(); inputTypeHint = null; } // inputType may be more specific than default the generator chooses below. if (!output.Attributes.ContainsName("type")) { output.Attributes.SetAttribute("type", inputType); } TagBuilder tagBuilder; switch (inputType) { case "checkbox": GenerateCheckBox(modelExplorer, output); return; case "hidden": tagBuilder = Generator.GenerateHidden( ViewContext, modelExplorer, For.Name, value: For.Model, useViewData: false, htmlAttributes: null); break; case "password": tagBuilder = Generator.GeneratePassword( ViewContext, modelExplorer, For.Name, value: null, htmlAttributes: null); break; case "radio": tagBuilder = GenerateRadio(modelExplorer); break; default: tagBuilder = GenerateTextBox(modelExplorer, inputTypeHint, inputType); break; } if (tagBuilder != null) { ServiceContext serviceContext = ViewContext.ViewBag.ServiceContext; string modelPath = serviceContext.RootName + "." + ModelHelper.GetMetadataModelPath(For.Name); ElementMetadata elementData = null; if (serviceContext?.ServiceMetaData.Elements.ContainsKey(modelPath) == true) { elementData = serviceContext.ServiceMetaData.Elements[modelPath]; } if (elementData != null && elementData.IsReadOnly) { output.Attributes.Add("disabled", null); } // This TagBuilder contains the one <input/> element of interest. Since this is not the "checkbox" // special-case, output is a self-closing element no longer guaranteed. output.MergeAttributes(tagBuilder); output.Content.AppendHtml(tagBuilder.InnerHtml); ReplaceAttributeTextKeysWithText(output, serviceContext); } }
/// <inheritdoc /> public override void Process(TagHelperContext context, TagHelperOutput output) { string inputType; string? inputTypeHint; ModelExplorer modelExplorer = For.ModelExplorer; IDictionary <string, object>?htmlAttributes = null; // Pass through attributes that are also well-known HTML attributes. // Must be done prior to any copying from a TagBuilder. if (InputTypeName is not null) { output.CopyHtmlAttribute("type", context); } if (Name is not null) { output.CopyHtmlAttribute(nameof(Name), context); } if (Value is not null) { output.CopyHtmlAttribute(nameof(Value), context); } output.Attributes.SetAttribute(nameof(Appearance), Appearance.ToString().ToLowerInvariant()); if (string.IsNullOrEmpty(InputTypeName)) { // Note GetInputType never returns null. inputType = GetInputType(modelExplorer, out inputTypeHint); } else { inputType = InputTypeName.ToLowerInvariant(); inputTypeHint = null; } // inputType may be more specific than default the generator chooses below. if (output.Attributes.ContainsName("type") != true) { output.Attributes.SetAttribute("type", inputType); } // Ensure Generator does not throw due to empty "fullName" if user provided a name attribute. if (string.IsNullOrEmpty(For.Name) && string.IsNullOrEmpty(ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix) && string.IsNullOrEmpty(Name) != true) { htmlAttributes = new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase) { { "name", Name }, }; } TagBuilder tagBuilder = inputType switch { "password" => GeneratePasswordField(modelExplorer, htmlAttributes), _ => GenerateTextField(modelExplorer, inputTypeHint, inputType, htmlAttributes), }; output.MergeAttributes(tagBuilder); }
public TagBuilder ProcessTagBuilder(TagHelperContext context, TagHelperOutput output) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } // Pass through attributes that are also well-known HTML attributes. Must be done prior to any copying // from a TagBuilder. // NP: Had to add && context.AllAttributes.ContainsName("type") because CopyHtmlAttribute expects value in context attributes // issue is that we already set the InputTypeName in the constructor (with our different usage). I THINK these values // are only set if THE USER sent in a value in the tags... if (InputTypeName != null && context.AllAttributes.ContainsName("type")) { output.CopyHtmlAttribute("type", context); } if (Value != null && context.AllAttributes.ContainsName(nameof(Value))) { output.CopyHtmlAttribute(nameof(Value), context); } // Note null or empty For.Name is allowed because TemplateInfo.HtmlFieldPrefix may be sufficient. // IHtmlGenerator will enforce name requirements. var metadata = For.Metadata; var modelExplorer = For.ModelExplorer; if (metadata == null) { ThrowExOnMetadataNull(ForAttributeName, For.Name); } string inputType; string inputTypeHint; if (string.IsNullOrEmpty(InputTypeName)) { // Note GetInputType never returns null. inputType = GetInputType(modelExplorer, out inputTypeHint); } else { inputType = InputTypeName.ToLowerInvariant(); inputTypeHint = null; } // inputType may be more specific than default the generator chooses below. if (!output.Attributes.ContainsName("type")) { output.Attributes.SetAttribute("type", inputType); } TagBuilder tagBuilder; switch (inputType) { case "hidden": tagBuilder = GenerateHidden(modelExplorer, null); break; case "checkbox": tagBuilder = GenerateCheckBox(modelExplorer, output, null); break; case "password": tagBuilder = Generator.GeneratePassword( ViewContext, modelExplorer, For.Name, value: null, htmlAttributes: null); break; case "radio": tagBuilder = GenerateRadio(modelExplorer, null); break; default: tagBuilder = GenerateTextBox(modelExplorer, inputTypeHint, inputType, null); break; } return(tagBuilder); }
public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { var inputType = string.IsNullOrEmpty(InputTypeName) ? GetInputType(For.ModelExplorer, out _) : InputTypeName.ToLowerInvariant(); if (inputType != "checkbox") { output.AddClass("form-control", HtmlEncoder.Default); } return(Task.CompletedTask); }