也许duplicate of this已经,但由于那篇文章没有任何答案,我发布这个问题。
新的Razor Class Library很棒,但它无法打包库文件(如jQuery,共享CSS)。
我可以以多种方式在多个Razor Page项目中重复使用CSS,使用Razor类库或其他任何东西(我的目的是,多个网站使用相同的CSS,并且单个更改适用于所有项目)。
我尝试在Razor类库项目中创建文件夹wwwroot
,但它没有按预期工作(我可以理解为什么)。
您需要将静态资源嵌入Razor类库程序集中。我认为如何做到最好的方法是看看ASP.NET Identity UI source codes。
您应该采取以下4个步骤来嵌入资产并为其提供服务。
<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>
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);
}
}
services.ConfigureOptions(typeof(UIConfigureOptions));
<script src="~/js/app.bundle.js" asp-append-version="true"></script>
感谢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}")));
}
}
}
我很久以前就达成了这个问题。您可以按照文章how to include static files in a razor library解释如何解决此问题。
我经过大量调查后得出的解决方案与此问题中接受的答案相差不远:
<ItemGroup>
<EmbeddedResource Include="wwwroot\**\*" />
<EmbeddedResource Include="Areas\*\wwwroot\**\*" />
</ItemGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
</PropertyGroup>
(您可以在链接文章中找到更多详细信息,甚至可以从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
文件夹中的所有嵌入资源。
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);
有一个更简单的解决方案:在您的RCL项目中,您可以标记要复制到发布目录的wwwroot
:
<ItemGroup>
<Content Include="wwwroot\**\*.*" CopyToPublishDirectory="Always" />
</ItemGroup>
部署依赖于RCL的应用程序时,可以按预期访问所有文件。你只需要小心没有命名冲突。
警告:这仅适用于在Azure上部署,但不适用于本地计算机(您需要提供商)。