我在 wwwroot
中有一个包含静态文件的 ASP.NET Core 项目目录和 bower_components
目录。
我可以通过将它添加到我的 Startup.cs
来为这些文件提供服务。类(class):
StaticFileOptions rootFileOptions = new StaticFileOptions();
rootFileOptions.OnPrepareResponse = staticFilesResponseHandler;
StaticFileOptions bowerFileOptions = new StaticFileOptions();
bowerFileOptions.OnPrepareResponse = staticFilesResponseHandler;
string bowerDirectory = Path.Combine(Directory.GetCurrentDirectory(), "bower_components");
PhysicalFileProvider bowerPhysicalFileProvider = new PhysicalFileProvider(bowerDirectory);
bowerFileOptions.FileProvider = bowerPhysicalFileProvider;
bowerFileOptions.RequestPath = new PathString("/bower");
app.UseStaticFiles(rootFileOptions);
app.UseStaticFiles(bowerFileOptions);
然后从我的观点中引用它们如下:
<script type="text/javascript" src="/bower/jquery/dist/jquery.min.js" asp-append-version="true"></script>
<script type="text/javascript" src="/Libs/jQuery-UI/jquery-ui.min.js" asp-append-version="true"></script>
即使
asp-append-version
对于位于 wwwroot
下的资源似乎工作得很好,对于 wwwroot
之外的资源,它似乎完全被忽略了.尽管如此,所有资源都得到了适当的服务;没有 404 或任何东西。上述代码的结果 HTML 如下:<script type="text/javascript" src="/bower/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="/Libs/jQuery-UI/jquery-ui.min.js?v=YZKMNaPD9FY0wb12QiluqhIOWFhZXnjgiRJoxErwvwI"></script>
我究竟做错了什么?
最佳答案
这个问题很老了,但问题仍然存在,虽然 Artak 提供的解决方案有效,但在大多数情况下它在概念上是不正确的。首先让我们看看问题的根源:asp-append-version
使用 IHostingEnvironment.WebRootFileProvider
查找文件默认情况下是 PhysicalFileProvider
指向wwwroot
文件夹。
核心文档有一个关于如何 serve files outside of web root 的示例:
public void Configure(IApplicationBuilder app)
{
app.UseStaticFiles(); // For the wwwroot folder
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
}
这允许您从
wwwroot
中服务器静态文件和 MyStaticFiles
文件夹。如果您有图片 \MyStaticFiles\pic1.jpg
,您可以通过两种方式引用它:<img src="~/pic1.jpg" />
<img src="~/StaticFiles/pic1.jpg" />
两者都将同样有效。这在概念上是不正确的,因为您为路径指定了别名
/StaticFiles
,因此其文件不应与根 /
合并.但至少它有效,它给了你你想要的。遗憾的是,
asp-append-version
不知道这一切。它应该,但它没有。应该是因为它旨在与静态文件(JavaScript、CSS 和图像)一起使用,所以如果我们更改配置以提供来自不同文件夹的静态文件,那么 asp-append-version
是有道理的。获取这些配置的副本。没有,所以我们需要通过修改IHostingEnvironment.WebRootFileProvider
单独配置.Artak 建议使用
CompositeFileProvider
这允许我们将多个文件提供者分配给 IHostingEnvironment.WebRootFileProvider
.这确实有效,但它有一个根本问题。 CompositeFileProvider
不允许我们定义 RequestPath
喜欢在 StaticFileOptions
.作为一种解决方法,Artak 建议我们不应该使用前缀,这利用了上述错误行为,即文件可以通过两种方式引用。为了演示这个问题,假设另一个文件夹具有如下结构:|_ MyStaticFiles |_ HTML | |_ privacy.html | |_ faq.html |_ images |_ image1.jpg
Now, what happens to all files in the MyStaticFiles\images
folder? Assuming that wwwroot
also has images
folder, will it work or give you an error for two identically named folders? Where will the file ~/images/image1.jpg
be coming from?
Regardless of whether it works or not, there is often an important reason for why you have your static files in a folder other than wwwroot
. It is often because those static files are for example content files that you don't want mixed with website design files.
We need a provider that allows us to specify the RequestPath
for each folder. Since Core doesn't currently have such provider, we're only left with the option of writing our own. Although not difficult, it's not a task that many programmers like to tackle. Here is a quick implementation, it's not perfect, but it does the job. It is based on the example provided by Marius Zkochanowski with some inhancements:
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Primitives;
namespace Microsoft.Extensions.FileProviders {
class CompositeFileWithOptionsProvider : IFileProvider {
private readonly IFileProvider _webRootFileProvider;
private readonly IEnumerable<StaticFileOptions> _staticFileOptions;
public CompositeFileWithOptionsProvider(IFileProvider webRootFileProvider, params StaticFileOptions[] staticFileOptions)
: this(webRootFileProvider, (IEnumerable<StaticFileOptions>)staticFileOptions) { }
public CompositeFileWithOptionsProvider(IFileProvider webRootFileProvider, IEnumerable<StaticFileOptions> staticFileOptions) {
_webRootFileProvider = webRootFileProvider ?? throw new ArgumentNullException(nameof(webRootFileProvider));
_staticFileOptions = staticFileOptions;
}
public IDirectoryContents GetDirectoryContents(string subpath) {
var provider = GetFileProvider(subpath, out string outpath);
return provider.GetDirectoryContents(outpath);
}
public IFileInfo GetFileInfo(string subpath) {
var provider = GetFileProvider(subpath, out string outpath);
return provider.GetFileInfo(outpath);
}
public IChangeToken Watch(string filter) {
var provider = GetFileProvider(filter, out string outpath);
return provider.Watch(outpath);
}
private IFileProvider GetFileProvider(string path, out string outpath) {
outpath = path;
var fileProviders = _staticFileOptions;
if (fileProviders != null) {
foreach (var item in fileProviders) {
if (path.StartsWith(item.RequestPath, StringComparison.Ordinal)) {
outpath = path.Substring(item.RequestPath.Value.Length, path.Length - item.RequestPath.Value.Length);
return item.FileProvider;
}
}
}
return _webRootFileProvider;
}
}
}
现在我们可以更新 Artak 的示例以使用新的提供程序:
app.UseStaticFiles(); //For the wwwroot folder.
//This serves static files from the given folder similar to IIS virtual directory.
var options = new StaticFileOptions {
FileProvider = new PhysicalFileProvider(Configuration.GetValue<string>("ContentPath")),
RequestPath = "/Content"
};
//This is required for asp-append-version (it needs to know where to find the file to hash it).
env.WebRootFileProvider = new CompositeFileWithOptionsProvider(env.WebRootFileProvider, options);
app.UseStaticFiles(options); //For any folders other than wwwroot.
在这里,我从配置文件中获取路径,因为它通常甚至完全位于应用程序文件夹之外。现在您可以使用
/Content
引用您的内容文件而不是 ~/
.例子:<img src="~/Content/images/pic1.jpg" asp-append-version="true" />
关于c# - ASP.NET Core asp-append-version 属性不适用于 wwwroot 目录之外的静态文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42775181/