This repository has been archived by the owner. It is now read-only.

asp-append-version attribute not working for static files outside of the wwwroot directory #7459

Closed
mariuszkochanowski opened this Issue Mar 8, 2018 · 4 comments

Comments

Projects
None yet
3 participants
@DamianEdwards

This comment has been minimized.

Copy link
Member

DamianEdwards commented Mar 9, 2018

This is currently by design. The asp-append-version attribute limits its searching for files to the configured HostingEnvironment.WebRootFileProvider, as that is the place that static files are expected to be served from. While you may be manually adding static file middleware instances that look elsewhere, there's no way for the Tag Helper to know that, as it only has access to the relative path you've provided (which is from the point of view of the browser) and the configured WebRootFileProvider.

We could potentially add the ability to set the file provider to use on the Tag Helper itself, e.g. <script src="/bower/jquery/dist/jquery.min.js" asp-append-file-version="true" asp-file-provider="@someFileProvider"></script>, but that seems as though it would be cumbersome to use, given that file providers like this are generally configured in the application's Startup.Configure method and not rooted in a way that can be easily referenced by the Razor files where the Tag Helper is being invoked.

I'd recommend you instead try wrapping the default HostingEnvironment.WebRootFileProvider with something like an AggregatePhysicalFileProvider, that can take multiple physical folder path "roots", and return results from all of them, then set that as the HostingEnvironment.WebRootFileProvider when building the WebHostBuilder.

@mkArtakMSFT

This comment has been minimized.

Copy link
Contributor

mkArtakMSFT commented Mar 9, 2018

Hi @mariuszkochanowski. Using the suggestion provided by @DamianEdwards I could successfully configure a CompositeFileProvider and get version string appended to both of the files I've referred to. I've shared the sample project at: https://github.com/mkArtakMSFT/Samples/tree/master/AppendVersionMultipleRoots/StaticFilesAppendVersion

Here is the setup I've used in in Configure method:

app.UseStaticFiles();

var compositeProvider = new CompositeFileProvider(
    env.WebRootFileProvider,
    new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "StaticFiles")));
env.WebRootFileProvider = compositeProvider;
var options = new StaticFileOptions()
{
    FileProvider = compositeProvider,
    RequestPath = "/StaticFiles"
};
app.UseStaticFiles(options);

And the markup used to refer to the files looks like this:

<script type="text/javascript" src="~/js/site.js" asp-append-version="true"></script>
<script type="text/javascript" src="~/Special.js" asp-append-version="true"></script>

The Special.js static file is located under the StaticFiles root folder, and I don't include the prefix to that path, as the server will look into that folder at the root level.

@mkArtakMSFT mkArtakMSFT added the question label Mar 9, 2018

@mariuszkochanowski

This comment has been minimized.

Copy link

mariuszkochanowski commented Mar 11, 2018

@mkArtakMSFT based on your suggestion i created provider that allows me use normal paths:

class CompositeFileProviderExtended : IFileProvider
    {
        private readonly IFileProvider _webRootFileProvider;
        private readonly StaticFileOptions[] _staticFileOptions;

        public CompositeFileProviderExtended(IFileProvider webRootFileProvider, StaticFileOptions[] staticFileOptions)
        {
            _webRootFileProvider = webRootFileProvider ?? throw new ArgumentNullException(nameof(webRootFileProvider));
            _staticFileOptions = staticFileOptions;
        }

        public IDirectoryContents GetDirectoryContents(string subpath)
        {
            string outpath;
            var provider = GetFileProvider(subpath, out outpath);

            return provider.GetDirectoryContents(outpath);
        }

        public IFileInfo GetFileInfo(string subpath)
        {
            string outpath;
            var provider = GetFileProvider(subpath, out outpath);

            return provider.GetFileInfo(outpath);
        }

        public IChangeToken Watch(string filter)
        {
            string outpath;
            var provider = GetFileProvider(filter, out outpath);

            return provider.Watch(outpath);
        }

        internal IFileProvider GetFileProvider(string path, out string outpath)
        {
            outpath = path;

            var fileProviders = _staticFileOptions;
            if (fileProviders != null)
            {
                for (var index = 0; index < fileProviders.Length; index++)
                {
                    var item = fileProviders[index];

                    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;
        }
    }
@mkArtakMSFT

This comment has been minimized.

Copy link
Contributor

mkArtakMSFT commented Mar 11, 2018

Glad it worked out, @mariuszkochanowski.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.