Razor类库也可以打包静态文件(js,css等)吗?

问题描述 投票:9回答:3

也许duplicate of this已经,但由于那篇文章没有任何答案,我发布这个问题。

新的Razor Class Library很棒,但它无法打包库文件(如jQuery,共享CSS)。

我可以以多种方式在多个Razor Page项目中重复使用CSS,使用Razor类库或其他任何东西(我的目的是,多个网站使用相同的CSS,并且单个更改适用于所有项目)。

我尝试在Razor类库项目中创建文件夹wwwroot,但它没有按预期工作(我可以理解为什么)。

c# asp.net-mvc asp.net-core reusability razor-pages
3个回答
12
投票

您需要将静态资源嵌入Razor类库程序集中。我认为如何做到最好的方法是看看ASP.NET Identity UI source codes

您应该采取以下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. 使依赖Web应用程序使用您的Razor类库路由器。在Startup Class的ConfigureServices方法中,添加以下行。 services.ConfigureOptions(typeof(UIConfigureOptions));
  4. 所以,现在您可以添加对文件的引用。 (我们假设它位于wwwroot / js / app.bundle.js)。 <script src="~/js/app.bundle.js" asp-append-version="true"></script>

1
投票

感谢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}")));
        }
    }
}

0
投票

我很久以前就达成了这个问题。您可以按照文章how to include static files in a razor library解释如何解决此问题。

我经过大量调查后得出的解决方案与此问题中接受的答案相差不远:

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

(您可以在链接文章中找到更多详细信息,甚至可以从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();

这将提取位于相关路径中的wwwroot文件夹中的所有嵌入资源。

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
投票

有一个更简单的解决方案:在您的RCL项目中,您可以标记要复制到发布目录的wwwroot

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

部署依赖于RCL的应用程序时,可以按预期访问所有文件。你只需要小心没有命名冲突。

警告:这仅适用于在Azure上部署,但不适用于本地计算机(您需要提供商)。

© www.soinside.com 2019 - 2024. All rights reserved.