объединить HtmlAttributes в ядре asp.net

Я некоторое время использовал метод MergeHtmlAttributes Html Helper Extension Криса Пратта в своих шаблонах редактора asp.net mvc 5. Я начал процесс переключения приложения на ядро ​​Asp.net 1.1 (.net framework 4.5.2). И htmlhelperExtension у меня не работает.

public static partial class HtmlHelperExtensions
{
    //https://cpratt.co/html-editorfor-and-htmlattributes/
    public static IDictionary<string, object> MergeHtmlAttributes(this HtmlHelper helper, object htmlAttributesObject, object defaultHtmlAttributesObject)
    {
        var concatKeys = new string[] { "class" };

        var htmlAttributesDict = htmlAttributesObject as IDictionary<string, object>;
        var defaultHtmlAttributesDict = defaultHtmlAttributesObject as IDictionary<string, object>;

        RouteValueDictionary htmlAttributes = (htmlAttributesDict != null)
            ? new RouteValueDictionary(htmlAttributesDict)
            : HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributesObject);

        RouteValueDictionary defaultHtmlAttributes = (defaultHtmlAttributesDict != null)
            ? new RouteValueDictionary(defaultHtmlAttributesDict)
            : HtmlHelper.AnonymousObjectToHtmlAttributes(defaultHtmlAttributesObject);

        foreach (var item in htmlAttributes)
        {
            if (concatKeys.Contains(item.Key))
            {
                defaultHtmlAttributes[item.Key] = (defaultHtmlAttributes[item.Key] != null)
                    ? string.Format("{0} {1}", defaultHtmlAttributes[item.Key], item.Value)
                    : item.Value;
            }
            else
            {
                if(item.Key?.ToString() == "divClass")
                {
                    continue;
                }
                defaultHtmlAttributes[item.Key] = item.Value;
            }
        }

        return defaultHtmlAttributes;
    }
}

Когда я копирую класс поверх него, он помечает статус: using System.Web.Mvc; -Не удается разрешить символ MVC. И после удаления этого оператора using я получаю сообщение, что не могу разрешить символ «HtmlHelper» в MergeHtmlAttributes(this HtmlHelper helper, ...). У меня есть возможность добавить либо Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper, либо .HtmlHelper<Tmodel>. Я выбрал .HtmlHelper. После этого он ссылается на строку RouteValueDictionary htmlAttributes = и говорит, что не может преобразовать IDictionary<string, object> в system.web.Routing.RouteValueDictionary. И я должен изменить тип на IDictionary<string, object> или привести к RouteValueDictionary. В любом случае я получаю следующую ошибку при попытке использовать MergeHtmlAttributes в одном из моих шаблонов редактора.

'IHtmlHelper<object>' не содержит определения для «MergeHtmlAttributes», а лучшая перегрузка метода расширения «HtmlHelperExtensions.MergeHtmlAttributes (HtmlHelper, объект, объект)» требует приемника типа «HtmlHelper»

Эта строка выдает ошибку-> var htmlAttributes = Html.MergeHtmlAttributes(ViewData, defaultHtmlAttributesObject);

Есть ли способ заставить это работать в ядре asp.net или есть другой метод для достижения тех же результатов? Вот пример одного из моих шаблонов редактора, чтобы вы могли видеть, как используются атрибуты MergeHtmlAttributes. Если я больше не могу создавать такой шаблон, есть ли более новый/лучший способ сделать это с помощью помощников по тегам? Мне очень нравится иметь labelfor, txtboxfor, ValidationMessageFor и т. д. все в одном помощнике html.

@model int?

@{
    var defaultHtmlAttributesObject = new { @class = "form-control" };
    var htmlAttributes = Html.MergeHtmlAttributes(ViewData, defaultHtmlAttributesObject);

    object divClass;
    ViewData.TryGetValue("divClass", out divClass);
    if (divClass == null) { divClass = ""; }

    IDictionary<string, object> validationAttributes = Html.GetUnobtrusiveValidationAttributes("");
    Html.ViewContext.FormContext.RenderedField(ViewData.TemplateInfo.GetFullHtmlFieldName(null), false);
}

<div class="form-group @divClass @(Html.ValidationErrorFor(x => x, " has-error"))">
    @Html.LabelFor(x => x, new { @class = "control-label" })
    @if (validationAttributes.ContainsKey("data-val-required"))
    {<span class="text-danger">*</span>}
    @Html.TextBoxFor(x => x, htmlAttributes)
    @Html.ValidationMessageFor(model => model, "", new { @class = "text-danger" })
</div>

F.Y.I. при преобразовании в asp.net core 1.1 (и .net framework 4.5.2) я в итоге поместил строку подключения в файл app.config, что позволило EF6 работать с ядром Asp.net, поэтому я могу продолжать использовать код EF, который у меня был построен, по какой-то причине он не нашел строку подключения в appsettings.json.


person Matt Lengenfelder    schedule 13.05.2017    source источник
comment
Я думаю, что определение функции должно быть: public static IDictionary‹string, object› MergeHtmlAttributes (этот помощник IHtmlHelper, объект htmlAttributesObject, объект defaultHtmlAttributesObject) Я нашел, как AnonymousObjectToHtmlAttributes раньше реализовывался на github здесь: ="nofollow noreferrer">github.com/aspnet/Mvc/blob/dev/src/   -  person Matt Lengenfelder    schedule 14.05.2017


Ответы (1)


Сначала я не знал, что Microsoft теперь использует IHtmlHelper вместо HtmlHelper.

Как только я модифицировал код, чтобы отразить это изменение, и нашел репозиторий Microsoft mvc на github, чтобы я смог найти их реализацию AnonymousObjectToHtmlAttributes, все совпало.

Приведенный ниже код работает для меня, но мне, возможно, придется внести некоторые изменения для крайних случаев, о которых я еще не подумал.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Routing;

using Microsoft.AspNetCore.Mvc.Rendering;

public static class HtmlHelperExtensions
{
    //http://cpratt.co/html-editorfor-and-htmlattributes/
    /// <summary>
    /// This is used with the EditorTemplates to copy the page element's htmlAttributes over to the editorTemplates 
    /// while still being able to specify values to always use (like @class = "form-control") in the editorTemplates.
    /// </summary>
    public static IDictionary<string, object> MergeHtmlAttributes(this IHtmlHelper helper, object htmlAttributesObject, object defaultHtmlAttributesObject)
    {
        var concatKeys = new[] { "class" };

        var htmlAttributesDict = htmlAttributesObject as IDictionary<string, object>;
        var defaultHtmlAttributesDict = defaultHtmlAttributesObject as IDictionary<string, object>;

        RouteValueDictionary htmlAttributes = new RouteValueDictionary(htmlAttributesDict != null
            ? htmlAttributesDict
            : AnonymousObjectToHtmlAttributes(htmlAttributesObject));

        RouteValueDictionary defaultHtmlAttributes = new RouteValueDictionary(defaultHtmlAttributesDict != null
            ? defaultHtmlAttributesDict
            : AnonymousObjectToHtmlAttributes(defaultHtmlAttributesObject));

        foreach (var item in htmlAttributes)
        {
            if (concatKeys.Contains(item.Key))
            {
                defaultHtmlAttributes[item.Key] = defaultHtmlAttributes[item.Key] != null
                    ? string.Format("{0} {1}", defaultHtmlAttributes[item.Key], item.Value)
                    : item.Value;
            }
            else
            {
                if(item.Key == "divClass")
                {
                    continue;
                }
                defaultHtmlAttributes[item.Key] = item.Value;
            }
        }

        return defaultHtmlAttributes;
    }

    private static IDictionary<string, object> AnonymousObjectToHtmlAttributes(object htmlAttributes)
    {
        var dictionary = htmlAttributes as IDictionary<string, object>;
        if (dictionary != null)
        {
            return new Dictionary<string, object>(dictionary, StringComparer.OrdinalIgnoreCase);
        }

        dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);

        if (htmlAttributes != null)
        {
            var stringAttributes = htmlAttributes.ToString();
            stringAttributes = stringAttributes.Replace("{", "").Replace("}", "");
            string[] attributesArray = stringAttributes.Split(new[] { ','}, StringSplitOptions.RemoveEmptyEntries);

            foreach (var helper in attributesArray)
            {
                string[] attribKeyValue = helper.Trim().Split(' ');
                dictionary[attribKeyValue.First()] = attribKeyValue.Last();
            }
        }

        return dictionary;
    }
}
person Matt Lengenfelder    schedule 14.05.2017
comment
Не должно быть = вместо пробела? string[] attribKeyValue = helper.Trim().Split(' '); - person Maxim; 08.08.2019
comment
Здесь: var htmlAttributes = Html.MergeHtmlAttributes(ViewData, DefaultHtmlAttributesObject); Блок кода выше, начинающийся с @model int? является лучшим примером того, как я его использовал. - person Matt Lengenfelder; 20.02.2020