Can Razor Class Library pack static files (js, css etc) too?

后端 未结 7 1787
陌清茗
陌清茗 2020-11-30 01:50

Maybe duplicate of this already, but since that post does not have any answer, I am posting this question.

The new Razor Class Library is awesome, but it cannot pack

相关标签:
7条回答
  • 2020-11-30 02:18

    Please take note that this solutions provided will only work for server side applications. If you are using Blazor client side it will not work. To include static assets on Blazor client side from a razor class library you need to reference directly the assets like this:

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

    I wasted hours trying to figure out this. Hope this helps someone.

    0 讨论(0)
  • 2020-11-30 02:24

    You need to embed your static assets into your Razor Class Library assembly. I think the best way to get how to do it is to take a look at ASP.NET Identity UI source codes.

    You should take the following 4 steps to embed your assets and serve them.

    1. Edit the csproj file of your Razor Class Library and add the following lines.

       <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. In your Razor Class Library, create the following class to serve and route the assets. (it assumes your assets are located at wwwroot folder)

      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. Make the dependent web application to use your Razor Class Library router. In the ConfigureServices method of Startup Class, add the following line.

      services.ConfigureOptions(typeof(UIConfigureOptions));
      
    4. So, now you can add a reference to your file. ( let's assume it's located at wwwroot/js/app.bundle.js).

      <script src="~/js/app.bundle.js" asp-append-version="true"></script>
      
    0 讨论(0)
  • 2020-11-30 02:29

    There's a simpler solution: in your RCL's project, you can flag the wwwroot to be copied to the publish directory:

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

    When you deploy an app that depends on the RCL, all the files are accessible as expected. You just need to be careful that there's no naming conflict.

    Caveat: this only works when deploying on Azure, but not on your local machine (you'll need a provider for that).

    0 讨论(0)
  • 2020-11-30 02:30

    Ehsan answer was correct at the time of asking (for .NET Core 2.2), for .NET Core 3.0, RCL can include static assets without much effort:

    To include companion assets as part of an RCL, create a wwwroot folder in the class library and include any required files in that folder.

    When packing an RCL, all companion assets in the wwwroot folder are automatically included in the package.

    The files included in the wwwroot folder of the RCL are exposed to the consuming app under the prefix _content/{LIBRARY NAME}/. For example, a library named Razor.Class.Lib results in a path to static content at _content/Razor.Class.Lib/.

    0 讨论(0)
  • 2020-11-30 02:34

    I reached this issue long time ago. You may follow the article how to include static files in a razor library that explains how to get around this issue.

    The solution I reached after a lot of investigation is not far from the accepted answer in this question:

    1 Set the files as embedded resources

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

    2 Include static files in the manifest

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

    3 Find the relevant folders

    (you can find more details in the linked article, even automatize this search from this article )

    // 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();
    

    This extracts all embedded resources in a wwwroot folder located in a relevant path.

    4 Add the found paths to the webroot file provider

    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 讨论(0)
  • 2020-11-30 02:39

    In .NET Core 3.1, RCL includes assets inside wwwroot folder to consuming app under _content/{LIBRARY NAME}.

    We can change _content/{LIBRARY NAME} path to different path name by editing RCL project propeties and placing StaticWebAssetBasePath.

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

    Now you can access files with /path/test.js.

    0 讨论(0)
提交回复
热议问题