/// <inheritdoc /> /// <remarks>Does nothing if <see cref="For"/> is <c>null</c>.</remarks> public override void Process(TagHelperContext context, TagHelperOutput output) { if (For == null) { // Regular HTML <select/> element. Just make sure Items wasn't specified. if (Items != null) { var message = Resources.FormatSelectTagHelper_CannotDetermineContentWhenOnlyItemsSpecified( "<select>", nameof(For).ToLowerInvariant(), nameof(Items).ToLowerInvariant()); throw new InvalidOperationException(message); } // Pass through attribute that is also a well-known HTML attribute. if (!string.IsNullOrEmpty(Multiple)) { output.CopyHtmlAttribute(nameof(Multiple), context); } } 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( "<select>", nameof(For).ToLowerInvariant(), nameof(IModelMetadataProvider), For.Name)); } bool allowMultiple; if (string.IsNullOrEmpty(Multiple)) { // Base allowMultiple on the instance or declared type of the expression. var realModelType = For.Metadata.RealModelType; allowMultiple = typeof(string) != realModelType && typeof(IEnumerable).IsAssignableFrom(realModelType); } else if (string.Equals(Multiple, "multiple", StringComparison.OrdinalIgnoreCase)) { allowMultiple = true; // Copy exact attribute name and value the user entered. Must be done prior to any copying from a // TagBuilder. Not done in next case because "true" and "false" aren't valid for the HTML 5 // attribute. output.CopyHtmlAttribute(nameof(Multiple), context); } else if (!bool.TryParse(Multiple.ToLowerInvariant(), out allowMultiple)) { throw new InvalidOperationException(Resources.FormatTagHelpers_InvalidValue_ThreeAcceptableValues( "<select>", nameof(Multiple).ToLowerInvariant(), Multiple, bool.FalseString.ToLowerInvariant(), bool.TrueString.ToLowerInvariant(), nameof(Multiple).ToLowerInvariant())); // acceptable value (as well as attribute name) } // Ensure GenerateSelect() _never_ looks anything up in ViewData. var items = Items ?? Enumerable.Empty <SelectListItem>(); var tagBuilder = Generator.GenerateSelect( ViewContext, For.Metadata, optionLabel: null, name: For.Name, selectList: items, allowMultiple: allowMultiple, htmlAttributes: null); if (tagBuilder != null) { output.SelfClosing = false; output.Merge(tagBuilder); } } }