Вспомогательный тег 'input' не должен иметь C# в области объявления атрибутов элемента.

Мы сталкиваемся со следующей ошибкой при сборке приложения ASP.NET Core MVC, которое недавно было перенесено с .NET Core 2.2 на 3.0:

Вспомогательный тег 'input' (или 'textarea' или любой другой) не должен иметь C# в области объявления атрибутов элемента.

Мы использовали Razor @functions для возврата содержимого атрибута HTML, чтобы преодолеть эту проблему, но это выглядит уродливо, когда вы используете переменную для возврата из функции без какой-либо дополнительной логики (функция dummy(htmlAttributeContent) возвращает htmlAttributeContent)

@{
    var roAttrHTML = "";
    if (!user.GotAccessToken("someToken")) {
        roAttrHTML = " readonly=\"readonly\" ";
    }
}
<textarea class="testClass" asp-for="testId" @readonlyAttribute>@Model.Id</textarea>

На самом деле мы получили ошибку

Вспомогательная функция тега textarea не должна содержать C# в области объявления атрибутов элемента.

при компиляции нашего приложения ASP.NET Core MVC, тогда как нам нужен подход (лучше без использования @functions), который даст нам способ преодолеть эту проблему (поскольку у нас есть множество страниц с похожей логикой, которые нам нужно коснуться один раз и избежать любых возможные проблемы с предполагаемыми новыми изменениями в поддержке атрибутов в будущих версиях .NET Core)


person Alexey    schedule 12.11.2019    source источник
comment
Как вы определили @readonlyAttribute? Я также мог получить ту же ошибку в ядре asp.net 2.2. Почему бы не попробовать readonly=@readonlyAttribute?   -  person Rena    schedule 13.11.2019
comment
@ Рена, это должен быть принятый ответ!   -  person MDummy    schedule 07.07.2020
comment
@MDummy на самом деле, это ничего не делает, потому что не имеет значения, какое значение есть для атрибута readonly, когда оно есть, поле доступно только для чтения   -  person Matus    schedule 01.05.2021


Ответы (5)


Я столкнулся с этой же проблемой при создании нового приложения 3.0. Старое приложение версии 2.2 позволяло мне указывать C# в объявлении, даже несмотря на то, что "это недопустимо"1.

Я создал свой собственный TagHelper2, выполнив следующие шаги:

  1. Создать файл: CustomAttributeTagHelper .cs
namespace {YourBaseNameSpace}.Helpers.TagHelpers
{
    using System.Collections.Generic;
    using Microsoft.AspNetCore.Razor.TagHelpers;

    [HtmlTargetElement(Attributes = "custom-attributes")]
    public class CustomAttributeTagHelper : TagHelper
    {
        public Dictionary<string, string> CustomAttributes { get; set; }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            if (CustomAttributes != null)
                foreach (var pair in CustomAttributes)
                    if (!output.Attributes.ContainsName(pair.Key))
                        output.Attributes.Add(pair.Key, pair.Value);
        }
    }
}
  1. Измените: /Pages/Shared/_ViewImports.cshtml, добавив строку ниже под собственной строкой Microsoft @addTagHelper.
@addTagHelper {YourBaseNameSpace}.Helpers.TagHelpers.*, {Your Assembly Name}

КЛЮЧЕВОЙ МОМЕНТ: убедитесь, что вы используете имя сборки, а не пространство имен после запятой выше

2а. Если вы не уверены, как называется ваша сборка, запустите приведенный ниже код в методе Program => Main(string[] args):

Type t = typeof({YourBaseNameSpace}.Helpers.TagHelpers.CustomAttributeTagHelper);
string s = t.Assembly.GetName().Name.ToString();
Console.WriteLine($"The fully qualified assembly name you need is: {s}.");
  1. Затем вы используете его так же просто, как на странице бритвы:
@{
    Dictionary<string, string> myCustomAttributes = new Dictionary<string, string> {
        ["data-first-custom-attribute"] = "my custom value"
    };

    if (!user.GotAccessToken("someToken")) {
        myCustomAttributes.Add("readonly","readonly");
    }
}

<input custom-attributes="myCustomAttributes" />

ПРИМЕЧАНИЕ. Этот код можно использовать в любом TagHelper, и это означает, что вы можете добавлять любые настраиваемые атрибуты по своему усмотрению.

Если вы хотите сделать это только для одного атрибута (например, только для чтения выше), вы можете создать условный TagHelper, для которого требуется логическое значение при построении или в качестве его значения.

person glenn223    schedule 03.01.2020
comment
Какая боль в заднице. - person tnk479; 07.05.2020
comment
Это отличное решение этой проблемы. Класс можно улучшить, добавив поддержку указания атрибутов через анонимные объекты, используя HtmlHelper.AnonymousObjectToHtmlAttributes(CustomAttributes); - person Mark Lagendijk; 28.04.2021

Вы можете сделать это следующим образом:

@if (!user.GotAccessToken("someToken")) 
{
   <textarea class="testClass" asp-for="testId" readonly>@Model.Id</textarea>
}
else
{
   <textarea class="testClass" asp-for="testId">@Model.Id</textarea>
}
person Matus    schedule 01.05.2021

Для той же проблемы, но с несколькими атрибутами, я сделал следующее обходное решение:

@{
    //...
    string attributes = "...prepare attributes ...";
    string tag = "<input " + attributes + " />";
    <text>@Html.Raw(tag)</text>
    //...
}

@Html.Raw не рекомендуется из-за некоторых уязвимостей безопасности, но я все же использовал его здесь. Помните об этом риске. При необходимости я могу поделиться некоторыми дополнительными статьями об этом риске. В противном случае для одного атрибута я согласен с комментарием @Rena.

person Vedran    schedule 05.11.2020

Я закончил тем, что удалил строку

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 

из _ViewImports.cshtml

В моем случае мне пришлось создавать html с большой точностью, и я все равно не использовал TagHelpers.

person Hans Karlsen    schedule 13.12.2020

Если вам не нужно использовать TagHelper, вы можете использовать <!elementName>, чтобы отключить его для определенного элемента:

<!textarea class="testClass" asp-for="testId" @readonlyAttribute>@Model.Id</!textarea>

См. ответ @glenn223 для более структурного решения. Я сделал улучшенную версию своего решения, добавив поддержку анонимных объектов:

using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;

namespace  {YourBaseNameSpace}.Helpers.TagHelpers
{
    [HtmlTargetElement(Attributes = "custom-attributes")]
    public class CustomAttributesTagHelper : TagHelper
    {
        public object CustomAttributes { get; set; }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            var customAttributesDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(CustomAttributes);
            foreach (var (key, value) in customAttributesDictionary)
            {
                output.Attributes.SetAttribute(key, value);
            }
        }
    }
}
person Mark Lagendijk    schedule 28.04.2021