Дружим System.Web.Optimization Bundle с Windows Azure Storage

в 14:42, , рубрики: .net, azure, blob, caching, windows, windows azure, метки: , , , ,

Дружим System.Web.Optimization Bundle с Windows Azure StorageЯ все ждал, ждал, ждал, когда же все-таки умные ребята, разрабатывающие System.Web.Optimization добавят поддержку автоматической загрузки содержимого бандла в контейнер Azure Storage. На днях вышла «1.0.0-beta2», но желаемого функционала так я и не нашел, а быстроты то хочется...

Как использовать?

<head>
    @BlobStorageProvider.Render("~/mainlayout", BlobStorageProvider.ContentType.Style)
</head>

Как работает?

/// <summary>
/// Ссылка на кеш-хранилище Blob'а
/// </summary>
private const string CachedStorageLink = "http://cdn.m6lab.com/{0}/{1}";

В вышеприведенном коде указана ссылка на привязанный Caching к Blob'у. Скорость отклика у Blob'а оставляет желать лучшего, поэтому рекомендую использовать Caching для получения данных из Blob'а.

Сделать override на функцию, создающую Bundle не представляется возможным, поэтому пришлось использовать костыль:

// Данные файла на сервере
var content = new WebClient().DownloadString("{URL Вашего сайта}" + url);

Исходный код целиком:

public class BlobStorageProvider {
    /// <summary>
    /// Перечисление возможных типов загружаемого контента
    /// </summary>
    public enum ContentType {
        Script,
        Style
    }

    /// <summary>
    /// Ссылка на кеш-хранилище Blob'а
    /// </summary>
    private const string CachedStorageLink = "http://cdn.m6lab.com/{0}/{1}";

    /// <summary>
    /// Название Blob-хранилища
    /// </summary>
    private const string ContainerName = "robofollower";

    /// <summary>
    /// Настройки подключения к Blob'у
    /// </summary>
    private static readonly CloudStorageAccount StorageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName={Storage Account};AccountKey={Primary Key}");

    /// <summary>
    /// Контейнер Blob'a
    /// </summary>
    private static readonly CloudBlobContainer Container = StorageAccount.CreateCloudBlobClient().GetContainerReference(ContainerName);

    /// <summary>
    /// Контейнер ссылок на CDN
    /// </summary>
    private static readonly Dictionary<string, string> CdnLinks = new Dictionary<string, string>();

    /// <summary>
    /// Загруза данных в Blob-контейнер
    /// </summary>
    /// <param name="virtualPath"></param>
    /// <param name="contentType"></param>
    /// <returns></returns>
    private static void Upload(string virtualPath, ContentType contentType) {
        // Ссылка на файл на сервере
        var url = Scripts.Url(virtualPath);
        // Данные файла на сервере
        var content = new WebClient().DownloadString("{URL Вашего сайта}" + url);
        // Удаляем лишние знаки
        var formatted = url.ToString().Replace("/", "").Replace("?", "").Replace("v", "").Replace("=", "").Replace("-", "");

        var blobContentType = string.Empty;
        // Добавляем постфикс и настраиваем контейнер
        switch (contentType) {
            case ContentType.Script:
                formatted += ".js";
                blobContentType = "text/javascript";
                break;

            case ContentType.Style:
                formatted += ".css";
                blobContentType = "text/css";
                break;
        }

        // Референс блоба и его настройки
        var blob = Container.GetBlockBlobReference(formatted);
        blob.Properties.CacheControl = "public, max-age=3600";
        blob.Properties.ContentType = blobContentType;

        // Загрузка в контейнер
        blob.UploadFromStream(new MemoryStream(Encoding.ASCII.GetBytes(content)));

        // Добавляем в локальный контейнер ссылку
        CdnLinks.Add(virtualPath, string.Format(CachedStorageLink, ContainerName, formatted));
    }

    public static IHtmlString Render(string virtualPath, ContentType contentType) {

        if (!CdnLinks.ContainsKey(virtualPath))
            Upload(virtualPath, contentType);

        switch (contentType) {
            case ContentType.Style: {
                    var tag = new TagBuilder("link");
                    tag.MergeAttributes(new Dictionary<string, string> { { "href", CdnLinks[virtualPath] }, { "rel", "stylesheet" } });
                    return new HtmlString(tag.ToString(TagRenderMode.SelfClosing));
                }
            case ContentType.Script: {
                    var tag = new TagBuilder("script");
                    tag.MergeAttributes(new Dictionary<string, string> { { "src", CdnLinks[virtualPath] } });
                    return new HtmlString(tag.ToString(TagRenderMode.SelfClosing));
                }
        }

        return null;
    }
}

Автор: LuckyReveal

Источник

Поделиться

* - обязательные к заполнению поля