Подтвердить что ты не робот

Как работает JavaScript-версия (asp-append-version) в ASP.NET Core MVC

Похоже, что динамическое связывание не поддерживается в новой MVC (ссылка), и это должно быть сделано с помощью задачи gulp. MVC поддерживает некоторый новый атрибут asp-append-version, но я не нашел никаких объяснений о том, как он работает. Я подозреваю, что он вычисляет некоторый хэш содержимого файла и даже обновляет его после смены файла. Есть ли какая-либо документация о том, как она работает?

Мне также интересно, как он обнаруживает изменения файла или просто пересчитывает хэш каждый раз, когда MVC анализирует разметку бритвы.

4b9b3361

Ответ 1

Вы можете проверить исходный код LinkTagHelper, где вы увидите, что он в основном добавляет строку запроса версии к значению href через FileVersionProvider:

if (AppendVersion == true)
{
    EnsureFileVersionProvider();

    if (Href != null)
    {
        output.Attributes[HrefAttributeName].Value = _fileVersionProvider.AddFileVersionToPath(Href);
    }
}

private void EnsureFileVersionProvider()
{
    if (_fileVersionProvider == null)
    {
        _fileVersionProvider = new FileVersionProvider(
                HostingEnvironment.WebRootFileProvider,
                Cache,
                ViewContext.HttpContext.Request.PathBase);
    }
}

FileVersionProvider будет вычислять хэш содержимого файла с помощью алгоритма SHA256. Затем он закодирует URL-адрес и добавит его в строку запроса, как в:

path/to/file?v=B95ZXzHiOuQJzhBoHlSlNyN1_cOjJnz2DFsr-3ZyyJs

Хэш будет пересчитан только тогда, когда файл изменит, поскольку он добавлен в кеш, но с триггером истечения на основе наблюдателя файлов:

if (!_cache.TryGetValue(path, out value))
{
    value = QueryHelpers.AddQueryString(path, VersionKey, GetHashForFile(fileInfo));
    var cacheEntryOptions = new MemoryCacheEntryOptions().AddExpirationToken(_fileProvider.Watch(resolvedPath));
    _cache.Set(path, value, cacheEntryOptions);
}

Этот наблюдатель предоставляется HostingEnvironment.WebRootFileProvider, который реализует IFileProvider:

//
// Summary:
//     Creates a change trigger with the specified filter.
//
// Parameters:
//   filter:
//     Filter string used to determine what files or folders to monitor. Example: **/*.cs,
//     *.*, subFolder/**/*.cshtml.
//
// Returns:
//     An Microsoft.Framework.Caching.IExpirationTrigger that is triggered when a file
//     matching filter is added, modified or deleted.
IExpirationTrigger Watch(string filter);

Примечание. Вы можете сами просмотреть кешированные значения, проверив значения в IMemoryCache:

//give the link:
<link rel="stylesheet" asp-append-version="true" href="~/css/site.css" />

//You can check the cached version
this.Context.RequestServices.GetRequiredService<IMemoryCache>().Get("/css/site.css")

//Which will show a value like:
/css/site.css?v=B95ZXzHiOuQJzhBoHlSlNyN1_cOjJnz2DFsr-3ZyyJs

Ответ 2

В соответствии с текущей реализацией FileVersionProvider хэш добавляется только к относительному пути к файлу, например. <script src="~/js/jquery.min.js" asp-append-version="true"></script> В случае использования абсолютного пути, например. https://code.jquery.com/jquery-3.1.1.js хэш не будет добавлен.

Ответ 3

В Razor

var fileversion = '@this.AddFileVersionToPath("/js/components/forms.js")';

Метод расширения

using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.TagHelpers.Internal;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;

public static class IRazorPageExtensions
{
    public static string AddFileVersionToPath(this IRazorPage page, string path)
    {
        var context = page.ViewContext.HttpContext;
        IMemoryCache cache = context.RequestServices.GetRequiredService<IMemoryCache>();
        var hostingEnvironment = context.RequestServices.GetRequiredService<IHostingEnvironment>();
        var versionProvider = new FileVersionProvider(hostingEnvironment.WebRootFileProvider, cache, context.Request.Path);
        return versionProvider.AddFileVersionToPath(path);
    }
}