Некомпилированное частичное представление не наследуется от ViewImports

Я переместил часть вида в частичный вид.


_ViewImports.cshtml

@using AsonCore.Helpers
@using AsonCore.Models
@namespace AsonCore.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Application.cshtml

@page
@model ApplicationModel

<partial name="/Pages/Partial/_ApplicationPartial.cshtml" />

_ApplicationPartial.cshtml

@model ApplicationModel
<section class="content application">
    <div>
        <form method="post" enctype="multipart/form-data">
            <div>
                <label asp-for='email.Firstname'>FORNAVN</label>
                <input asp-for='email.Firstname' required />
            </div>
            <div>
                <label asp-for="email.Lastname">ETTERNAVN</label>
                <input asp-for="email.Lastname" required />
            </div>
            <div>
                <input type="submit" value="Send" />
            </div>
        </form>
        <partial name="/Pages/Shared/_FormScript.cshtml" />
    </div>
</section>

_Project.csproj

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
    <RootNamespace>AsonCore</RootNamespace>
  </PropertyGroup>

  <ItemGroup>
    <Content Remove="Pages\Partial\**" />
  </ItemGroup>

  <ItemGroup>
    <None Include="Pages\Partial\**">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
  </ItemGroup>

</Project>

При сборке частичные представления удаляются из скомпилированных views.dll, чтобы включить динамическое обновление их содержимого, и когда я это сделал, то, что изначально было унаследовано от _ViewImports.cshtml прекратилось.

Добавив @namespace AsonCore.Pages к частичному представлению, он выбрал Model, но затем, после развертывания на сервере (хотя она работает в VS2019), я заметил, что "TagHelpers" перестал работать.

Кроме того, добавление @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers к представлению исправило это, но мой вопрос: так ли это нужно/нужно делать?

Или есть какой-то другой способ предотвратить компиляцию определенных представлений, где сохраняется наследование от "ViewImports"?

Ответ 1

Вам нужно использовать следующее свойство в вашем csproj:

<PropertyGroup>
  <TargetFramework>netcoreapp2.1</TargetFramework>
  <RazorCompileOnBuild>false</RazorCompileOnBuild>
  <RazorCompileOnPublish>true</RazorCompileOnPublish>
</PropertyGroup>

Таким образом, файлы Razor прекомпилируются только во время публикации.

В зависимости от варианта использования конфигурации сборки вы также можете расширить его и использовать:

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
  <RazorCompileOnBuild>false</RazorCompileOnBuild>
  <RazorCompileOnPublish>true</RazorCompileOnPublish>
</PropertyGroup

Пожалуйста, следуйте документации MSDN для получения дополнительной информации по этому вопросу.


Я мог видеть вашу проблему:

 <PackageReference Include="Microsoft.AspNetCore.App" />

Как Microsoft объясняет:

Не добавляйте и не обновляйте явно ссылки на метапакет Microsoft.NETCore.App или NETStandard.Library в проектах .NET Framework. Если при использовании пакета NuGet на основе стандарта .NET требуется какая-либо версия NETStandard.Library, NuGet автоматически установит эту версию.

Взято из дополнений в формат csproj для .NET Core

Ответ 2

Преступник находится в классе TagHelperTypeResolver (класс, который находит допустимые теговые помощники в сборке) в пространстве имен Microsoft.AspNetCore.Razor.Runtime.TagHelpers.

По умолчанию TagSystem не выполняет поиск сборки TagHelper, зарегистрированной в системе Application Parts, она просто выполняет Assembly.Load(assemblyName) (см. Код ниже), поэтому даже если вы скомпилировали view.dll, ваши частичные представления выиграли не может ссылаться на TagHelper, на который ссылается ваш view.dll, потому что ваш view.dll при компиляции указывает на встроенную сборку Microsoft.AspNetCore.Mvc.TagHelpers, но, как и в случае вашего частичного представления, при компиляции нет ни директивы, которая указывает на view.dll, ни на сборку Microsoft.AspNetCore.Mvc.TagHelpers.

Поэтому добавление директивы @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers проблему, так как директива сообщает частичному представлению ссылку на сборку TagHelper. Когда ваше частичное представление скомпилировано, оно, вероятно, следует за пространством имен имени, которое совпадает с вашим файлом .csproj, то есть _Project, поэтому наследование может быть потеряно в результате другого пространства имен. Проверьте построенный вывод и посмотрите, так ли это.

Обратитесь к этой документации от Microsoft, там написано:

"Microsoft.AspNetCore.Mvc.TagHelpers - это сборка для встроенных основных помощников тегов ASP.NET".

https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro?view=aspnetcore-2.2

Когда директива @addTagHelper используется в вашем _ViewImports.cshtml, вы можете либо передать встроенные помощники по основным тегам ASP.NET, что делается следующим образом:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Или используйте внешнюю сборку:

@addTagHelper *, ExternalAssembly

Кроме того, еще одно возможное решение, вы можете попробовать изменить

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

в

@addTagHelper "*, Microsoft.AspNetCore.Mvc.TagHelpers"

в вашем _ViewImports.cshtml и посмотрите, работает ли он, так как он предпочитает строку.

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Razor.TagHelpers;

namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
{
    /// <summary>
    /// Class that locates valid <see cref="ITagHelper"/>s within an assembly.
    /// </summary>
    public class TagHelperTypeResolver : ITagHelperTypeResolver
    {
        private static readonly TypeInfo ITagHelperTypeInfo = typeof(ITagHelper).GetTypeInfo();

        /// <inheritdoc />
        public IEnumerable<Type> Resolve(
            string name,
            SourceLocation documentLocation,
            ErrorSink errorSink)
        {
            if (errorSink == null)
            {
                throw new ArgumentNullException(nameof(errorSink));
            }

            if (string.IsNullOrEmpty(name))
            {
                var errorLength = name == null ? 1 : Math.Max(name.Length, 1);
                errorSink.OnError(
                    documentLocation,
                    Resources.TagHelperTypeResolver_TagHelperAssemblyNameCannotBeEmptyOrNull,
                    errorLength);

                return Type.EmptyTypes;
            }

            var assemblyName = new AssemblyName(name);

            IEnumerable<TypeInfo> libraryTypes;
            try
            {
                libraryTypes = GetExportedTypes(assemblyName);
            }
            catch (Exception ex)
            {
                errorSink.OnError(
                    documentLocation,
                    Resources.FormatTagHelperTypeResolver_CannotResolveTagHelperAssembly(
                        assemblyName.Name,
                        ex.Message),
                    name.Length);

                return Type.EmptyTypes;
            }

            return libraryTypes.Where(IsTagHelper).Select(t => t.AsType());
        }

        /// <summary>
        /// Returns all exported types from the given <paramref name="assemblyName"/>
        /// </summary>
        /// <param name="assemblyName">The <see cref="AssemblyName"/> to get <see cref="TypeInfo"/>s from.</param>
        /// <returns>
        /// An <see cref="IEnumerable{TypeInfo}"/> of types exported from the given <paramref name="assemblyName"/>.
        /// </returns>
        protected virtual IEnumerable<TypeInfo> GetExportedTypes(AssemblyName assemblyName)
        {
            var assembly = Assembly.Load(assemblyName);

            return assembly.ExportedTypes.Select(type => type.GetTypeInfo());
        }

        /// <summary>
        /// Indicates if a <see cref="TypeInfo"/> should be treated as a tag helper.
        /// </summary>
        /// <param name="typeInfo">The <see cref="TypeInfo"/> to inspect.</param>
        /// <returns><c>true</c> if <paramref name="typeInfo"/> should be treated as a tag helper; 
        /// <c>false</c> otherwise</returns>
        protected virtual bool IsTagHelper(TypeInfo typeInfo)
        {
            if (typeInfo == null)
            {
                throw new ArgumentNullException(nameof(typeInfo));
            }

            return TagHelperConventions.IsTagHelper(typeInfo);
        }
    }
}

https://github.com/aspnet/Razor/blob/d337bacc69fe4ca39532d958712738c71f07c091/src/Microsoft.AspNetCore.Razor.Runtime/Runtime/TagHelpers/TagHelperTypeResolver.cs#L72

Ссылка TagHelper не наследуется представлением и должна быть явно установлена в представлении.

Для получения дополнительной информации в этой статье объясняется, как создать и расширить ITagHelperTypeResolver и реализовать его метод Resolve, чтобы настроить глобализацию в имени сборки, чтобы включить все TagHelpers, которые живут в сборках, соответствующих этому глобу. Если это поможет более подробно объяснить соответствие и глобализацию сборок TagHelper:

http://darrelltunnell.net/blog/2016/07/25/aspnet-core-taghelper-sa-better-addtaghelper-type-resolver/

Кредит: Даррелл Туннелл

Ответ 3

Я публикую этот ответ в качестве временного обходного пути (тем не менее, я надеюсь, что такой ответ объяснит, что происходит и где его найти в официальных ресурсах/документах).


Похоже, что он не сложнее, чем для скомпилированного частичного представления, он использует скомпилированный _ViewImports.cshtml, а для любого некомпилированного требуется копия _ViewImports.cshtml в расположении по умолчанию, в папке Pages\.

В моем случае как то так

\Pages\Partial\
  _Application.cshtml

\Pages\
  _ViewImports.cshtml

\
  AsonCore.Views.dll

Также оказывается, что можно взять любой другой скомпилированный файл основного вида (который не был удален при публикации, как я это делал с частичным представлением), скопировать его в папку Pages\, отредактировать, если хотите, и перезагрузит и переопределит скомпилированный файл, который находится в views.dll


Одно только выше будет отображаться в исключении, хотя (при попытке выполнить некомпилированные представления во время выполнения), но с помощью этого ответа это работает, который говорит:

Чтобы исправить это, вы должны опубликовать папку add refs подпапку с некоторыми сборками во время выполнения. Эта папка refs обычно создается, если вы публикуете проект с MvcRazorCompileOnPublish установлено значение false. Таким образом, вы должны один раз опубликовать без предварительной компиляции в другую папку и скопировать оттуда эту подпапку refs.

Обратите внимание, что может быть какой-то другой способ, чем использовать эту папку refs в Core 2.2, и если кто-то знает, пожалуйста, не стесняйтесь редактировать мой ответ с этим

Ответ 4

Код из _ViewImports.cshtml использует подстановочный синтаксис ("*"), чтобы указать, что все помощники тегов в указанной сборке (Microsoft.AspNetCore.Mvc.TagHelpers) будут доступны для каждого файла представления в каталоге или подкаталоге "Views". Если вы исключаете представление или представление происходит из внешнего проекта MVC (как EmbeddedResource), вы должны явно объявить его в каждом таком представлении.

Или попробуйте указать его как частичное представление в каждом таком представлении:

<partial name="~/Pages/_ViewImports.cshtml" />

_ViewImports.cshtml вставляется при компиляции и только если целевое представление скомпилировано относительно структуры папок, в _ViewImports.cshtml находится _ViewImports.cshtml. Возможно, когда скомпилированное представление скомпилировано, это происходит в другой папке, где _ViewImports.cshtml не виден или доступно.

Обновление: проблема может быть с параметрами компиляции во время выполнения в .NET Core 2.2. RazorViewEngineOptions AllowRecompilingViewsOnFileChange получает или задает значение, которое определяет, будут ли файлы Razor (представления Razor и страницы Razor) перекомпилированы и обновлены, если файлы изменяются на диске. В .NET Core 2.2 это значение истинно только в том случае, если EnvironmentName равно Development, отсюда различия, с которыми вы столкнулись в "после развертывания на сервере" против ", хотя он работает в VS2019" (более подробную информацию см. В RazorViewEngineOptions.AllowRecompilingViewsOnFileChange).