web-dev-qa-db-ja.com

Razorクラスライブラリは静的ファイル(js、cssなど)もパックできますか?

たぶん これの複製 はすでにありますが、その投稿には回答がないため、この質問を投稿しています。

新しい Razor Class Library はすばらしいですが、ライブラリファイル(jQuery、共有CSSなど)をパックできません。

Razorクラスライブラリなどを使用して、CSSを複数のRazorページプロジェクト間でどうにか再利用できますか(私の目的は、複数のWebサイトが同じCSSを使用し、1つの変更がすべてのプロジェクトに適用されることです)。

Razor Class Libraryプロジェクトでwwwrootフォルダーを作成しようとしましたが、期待どおりに機能しません(私はcan理由を理解しています動作しないはずです)。

23
Luke Vo

Ehsanの回答は、(。NET Core 2.2の場合)、. NET Core 3.0の場合 RCLは静的アセットを含めることができます に質問する時点で正解でした。

RCLの一部としてコンパニオンアセットを含めるには、クラスライブラリにwwwrootフォルダーを作成し、そのフォルダーに必要なファイルを含めます。

RCLをパックすると、wwwrootフォルダー内のすべてのコンパニオンアセットが自動的にパッケージに含まれます。

RCLのwwwrootフォルダーに含まれるファイルは、プレフィックス_content/{LIBRARY NAME} /の下で使用中のアプリに公開されます。たとえば、Razor.Class.Libという名前のライブラリは、_content/Razor.Class.Lib /にある静的コンテンツへのパスになります。

15
Luke Vo

静的アセットをRazorクラスライブラリアセンブリに埋め込む必要があります。それを行う方法を得る最良の方法は、 ASP.NET Identity UIソースコード を確認することだと思います。

アセットを埋め込み、提供するには、次の4つの手順を実行する必要があります。

  1. Razorクラスライブラリのcsprojファイルを編集し、次の行を追加します。

     <PropertyGroup>
      ....
           <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
      ....
     </PropertyGroup>
    
     <ItemGroup>
         ....
         <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.2" />
         <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.1.1" />
         <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="2.1.1" />
         <PackageReference Include="Microsoft.NET.Sdk.Razor" Version="$(MicrosoftNETSdkRazorPackageVersion)" PrivateAssets="All" />
        .....
     </ItemGroup>
    
    <ItemGroup>
        <EmbeddedResource Include="wwwroot\**\*" />
        <Content Update="**\*.cshtml" Pack="false" />
    </ItemGroup>
    
  2. Razorクラスライブラリで、アセットを提供およびルーティングする次のクラスを作成します。 (アセットがwwwrootフォルダにあると想定しています)

    public class UIConfigureOptions : IPostConfigureOptions<StaticFileOptions>
    {
        public UIConfigureOptions(IHostingEnvironment environment)
        {
            Environment = environment;
        }
        public IHostingEnvironment Environment { get; }
    
        public void PostConfigure(string name, StaticFileOptions options)
        {
            name = name ?? throw new ArgumentNullException(nameof(name));
            options = options ?? throw new ArgumentNullException(nameof(options));
    
            // Basic initialization in case the options weren't initialized by any other component
            options.ContentTypeProvider = options.ContentTypeProvider ?? new FileExtensionContentTypeProvider();
            if (options.FileProvider == null && Environment.WebRootFileProvider == null)
            {
                throw new InvalidOperationException("Missing FileProvider.");
            }
    
            options.FileProvider = options.FileProvider ?? Environment.WebRootFileProvider;
    
            var basePath = "wwwroot";
    
            var filesProvider = new ManifestEmbeddedFileProvider(GetType().Assembly, basePath);
            options.FileProvider = new CompositeFileProvider(options.FileProvider, filesProvider);
        }
    }
    
  3. Razorクラスライブラリルーターを使用する依存型Webアプリケーションを作成します。 StartupクラスのConfigureServicesメソッドで、次の行を追加します。

    services.ConfigureOptions(typeof(UIConfigureOptions));
    
  4. これで、ファイルへの参照を追加できるようになりました。 (wwwroot/js/app.bundle.jsにあるとしましょう)。

    <script src="~/js/app.bundle.js" asp-append-version="true"></script>
    
16
Ehsan Mirsaeedi

.NET Core 3.1では、RCLは_content/{LIBRARY NAME}の下の消費アプリへのwwwrootフォルダー内のアセットを含みます。

RCLプロジェクトプロパティを編集してStaticWebAssetBasePathを配置することにより、_content/{LIBRARY NAME}パスを別のパス名に変更できます。

PropertyGroup>
    <StaticWebAssetBasePath Condition="$(StaticWebAssetBasePath) == ''">/path</StaticWebAssetBasePath>
  </PropertyGroup>

これで、/ path/test.jsを使用してファイルにアクセスできます。

3
Vishwanath S

役立つ情報のEhsanをありがとう。

これは、javascriptとTypeScriptのデバッグを可能にする拡張バージョンで、再コンパイルせずに変更を加えることができます。 TypeScriptのデバッグはChrome=では機能しませんが、IEでは機能します。なぜかわからない場合は、返信を投稿してください。ありがとうございます。

public class ContentConfigureOptions : IPostConfigureOptions<StaticFileOptions>
{
    private readonly IHostingEnvironment _environment;

    public ContentConfigureOptions(IHostingEnvironment environment)
    {
        _environment = environment;
    }

    public void PostConfigure(string name, StaticFileOptions options)
    {
        // Basic initialization in case the options weren't initialized by any other component
        options.ContentTypeProvider = options.ContentTypeProvider ?? new FileExtensionContentTypeProvider();

        if (options.FileProvider == null && _environment.WebRootFileProvider == null)
        {
            throw new InvalidOperationException("Missing FileProvider.");
        }

        options.FileProvider = options.FileProvider ?? _environment.WebRootFileProvider;

        if (_environment.IsDevelopment())
        {
            // Looks at the physical files on the disk so it can pick up changes to files under wwwroot while the application is running is Visual Studio.
            // The last PhysicalFileProvider enalbles TypeScript debugging but only wants to work with IE. I'm currently unsure how to get TS breakpoints to hit with Chrome.
            options.FileProvider = new CompositeFileProvider(options.FileProvider, 
                                                             new PhysicalFileProvider(Path.Combine(_environment.ContentRootPath, $"..\\{GetType().Assembly.GetName().Name}\\wwwroot")),
                                                             new PhysicalFileProvider(Path.Combine(_environment.ContentRootPath, $"..\\{GetType().Assembly.GetName().Name}")));
        }
        else
        {
            // When deploying use the files that are embedded in the Assembly.
            options.FileProvider = new CompositeFileProvider(options.FileProvider, 
                                                             new ManifestEmbeddedFileProvider(GetType().Assembly, "wwwroot")); 
        }

        _environment.WebRootFileProvider = options.FileProvider; // required to make asp-append-version work as it uses the WebRootFileProvider. https://github.com/aspnet/Mvc/issues/7459
    }
}

public class ViewConfigureOptions : IPostConfigureOptions<RazorViewEngineOptions>
{
    private readonly IHostingEnvironment _environment;

    public ViewConfigureOptions(IHostingEnvironment environment)
    {
        _environment = environment;
    }

    public void PostConfigure(string name, RazorViewEngineOptions options)
    {
        if (_environment.IsDevelopment())
        {
            // Looks for the physical file on the disk so it can pick up any view changes.
            options.FileProviders.Add(new PhysicalFileProvider(Path.Combine(_environment.ContentRootPath, $"..\\{GetType().Assembly.GetName().Name}")));
        }
    }
}
1
KJ.Coding

より簡単な解決策があります。RCLのプロジェクトで、wwwrootにフラグを付けて、publishディレクトリにコピーすることができます。

<ItemGroup>
  <Content Include="wwwroot\**\*.*" CopyToPublishDirectory="Always" />
</ItemGroup>

RCLに依存するアプリをデプロイすると、すべてのファイルに期待どおりにアクセスできます。名前の競合がないように注意する必要があります。

警告:これはAzureにデプロイする場合にのみ機能しますが、ローカルマシンでは機能しません(そのためのプロバイダーが必要です)。

0
Métoule

提供されているこのソリューションはサーバー側のアプリケーションでのみ機能することに注意してください。 Blazorクライアント側を使用している場合は機能しません。かみそりクラスライブラリからBlazorクライアント側に静的アセットを含めるには、次のようにアセットを直接参照する必要があります。

<script src="_content/MyLibNamespace/js/mylib.js"></script>

これを理解しようと何時間も無駄にした。これが誰かを助けることを願っています。

0
revobtz

私はずっと前にこの問題に達しました。この問題を回避する方法を説明する記事 かみそりライブラリに静的ファイルを含める方法 に従うことができます。

多くの調査の後に私が到達した解決策は、この質問で受け入れられた答えからほど遠くない:

1ファイルを埋め込みリソースとして設定します

  <ItemGroup>
    <EmbeddedResource Include="wwwroot\**\*" />
    <EmbeddedResource Include="Areas\*\wwwroot\**\*" />
  </ItemGroup>

2マニフェストに静的ファイルを含める

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
  </PropertyGroup>

3関連するフォルダを見つける

(リンクされた記事で詳細を見つけることができます この記事 からこの検索を自動化することもできます)

// first we get the Assembly in which we want to embedded the files
var Assembly = typeof(TypeInFeatureAssembly).Assembly;

// we filter only files including a wwwroot name part
filePaths = (from rn in Assembly.GetManifestResourceNames().Where(rnn => rnn.Contains(".wwwroot."))
    let hasArea = rn.Contains(".Areas.")
    let root = rn.Substring(0, rn.LastIndexOf(".wwwroot.") + ".wwwroot.".Length)
    let rootPath = !hasArea ? root : root.Substring(0, root.IndexOf(".Areas."))
    let rootSubPath = !hasArea ? "" : root.Substring(root.IndexOf(".Areas.")).Replace('.', '/')
    select  hasArea ? rootSubPath.Substring(1, rootSubPath.Length - 2) : "wwwroot" )
    .Distinct().ToList();

これにより、関連するパスにあるwwwrootフォルダー内のすべての埋め込みリソースが抽出されます。

4見つかったパスをwebrootファイルプロバイダーに追加します。

var allProviders = new List<IFileProvider>();
allProviders.Add(env.WebRootFileProvider);
allProviders.AddRange(filePaths.Select(t => new ManifestEmbeddedFileProvider(t.Assembly, t.Path)));
env.WebRootFileProvider = new CompositeFileProvider(allProviders);

0
Jean