resource porta microsoft management azure asp.net-mvc-4 cdn bundling-and-minification asp.net-optimization

porta - Cómo subir archivos empaquetados y minificados a Windows Azure CDN



porta azure (4)

Entonces no hay una gran manera de hacer esto actualmente. El flujo de trabajo a más largo plazo que estamos visualizando es agregar compatibilidad de agrupación de compilación. Luego, ejecutaría una tarea de compilación (o ejecutaría un exe si lo prefiere) para generar los paquetes y luego podrá cargarlos en AzureCDN. Finalmente, acaba de activar UseCDN en BundleCollection, y los ayudantes de Script / Style simplemente cambiarán a renderizar enlaces a su AzureCDN con el repliegue adecuado a sus paquetes locales.

A corto plazo, lo que creo que está intentando hacer es cargar su paquete en AzureCDN cuando se crea el paquete por primera vez.

Un BundleTransform es una forma de hacerlo, supongo que es un truco, pero podrías agregar un BundleTransform último en tu paquete. Desde su último, BundleResponse.Content es efectivamente la respuesta final del paquete. En ese momento, puedes subirlo a tu CDN. ¿Tiene sentido?

Estoy usando las características de empaquetado y minificación de ASP.NET MVC 4 en el espacio de nombres Microsoft.AspNet.Web.Optimization (por ejemplo, @Styles.Render("~/content/static/css") ).

Me gustaría usarlo en combinación con un Windows Azure CDN.

BundleTransform escribir un BundleTransform personalizado pero el contenido aún no está optimizado.

También busqué en el análisis y la carga de la secuencia optimizada en tiempo de ejecución, pero eso me parece un truco y realmente no me gusta:

@StylesCdn.Render(Url.AbsoluteContent( Styles.Url("~/content/static/css").ToString() )); public static IHtmlString Render(string absolutePath) { // get the version hash string versionHash = HttpUtility.ParseQueryString( new Uri(absolutePath).Query ).Get("v"); // only parse and upload to CDN if version hash is different if (versionHash != _versionHash) { _versionHash = versionHash; WebClient client = new WebClient(); Stream stream = client.OpenRead(absolutePath); UploadStreamToAzureCdn(stream); } var styleSheetLink = String.Format( "<link href=/"{0}://{1}/{2}/{3}?v={4}/" rel=/"stylesheet/" type=/"text/css/" />", cdnEndpointProtocol, cdnEndpointUrl, cdnContainer, cdnCssFileName, versionHash ); return new HtmlString(styleSheetLink); }

¿Cómo puedo subir las versiones empaquetadas y minificadas de forma automática a mi Windows Azure CDN?


Para @manishKungwani solicitado en comentario anterior. Simplemente configure UseCdn y luego use la sobrecarga cdnHost para organizar el paquete. Lo usé para poner en un dominio de AWS CloudFront (xxx.cloudfront.net) pero en retrospectiva debería haber sido nombrado de manera más genérica para usar con cualquier otro proveedor de CDN.

public class CloudFrontScriptBundle : Bundle { public CloudFrontScriptBundle(string virtualPath, string cdnHost = "") : base(virtualPath, null, new IBundleTransform[] { new JsMinify(), new CloudFrontBundleTransformer { CdnHost = cdnHost } }) { ConcatenationToken = ";"; } } public class CloudFrontStyleBundle : Bundle { public CloudFrontStyleBundle(string virtualPath, string cdnHost = "") : base(virtualPath, null, new IBundleTransform[] { new CssMinify(), new CloudFrontBundleTransformer { CdnHost = cdnHost } }) { } } public class CloudFrontBundleTransformer : IBundleTransform { public string CdnHost { get; set; } static CloudFrontBundleTransformer() { } public virtual void Process(BundleContext context, BundleResponse response) { if (context.BundleCollection.UseCdn && !String.IsNullOrWhiteSpace(CdnHost)) { var virtualFileName = VirtualPathUtility.GetFileName(context.BundleVirtualPath); var virtualDirectory = VirtualPathUtility.GetDirectory(context.BundleVirtualPath); if (!String.IsNullOrEmpty(virtualDirectory)) virtualDirectory = virtualDirectory.Trim(''~''); var uri = string.Format("//{0}{1}{2}", CdnHost, virtualDirectory, virtualFileName); using (var hashAlgorithm = CreateHashAlgorithm()) { var hash = HttpServerUtility.UrlTokenEncode(hashAlgorithm.ComputeHash(Encoding.Unicode.GetBytes(response.Content))); context.BundleCollection.GetBundleFor(context.BundleVirtualPath).CdnPath = string.Format("{0}?v={1}", uri, hash); } } } private static SHA256 CreateHashAlgorithm() { if (CryptoConfig.AllowOnlyFipsAlgorithms) { return new SHA256CryptoServiceProvider(); } return new SHA256Managed(); } }


Puede definir el dominio de origen como el sitio web de Azure (esto probablemente se agregó mucho después de la pregunta original).

Una vez que tenga el punto final CDN, tendrá que permitir la cadena de consulta para él y luego puede hacer referencia directamente a los paquetes a través de CDN:

<link href="//az888888.vo.msecnd.net/Content/css-common?v=ioYVnAg-Q3qYl3Pmki-qdKwT20ESkdREhi4DsEehwCY1" rel="stylesheet"/>

También creé esta ayuda para agregar el nombre de host de CDN:

public static IHtmlString RenderScript(string virtualPath) { if (HttpContext.Current.IsDebuggingEnabled) return Scripts.Render(virtualPath); else return new HtmlString(String.Format( CultureInfo.InvariantCulture, Scripts.DefaultTagFormat, "//CDN_HOST" + Scripts.Url(virtualPath).ToHtmlString())); }


Siguiendo el consejo de Hao I Extended Bundle y IBundleTransform.

Agregar AzureScriptBundle o AzureStyleBundle a los paquetes;

bundles.Add(new AzureScriptBundle("~/bundles/modernizr.js", "cdn").Include("~/Scripts/vendor/modernizr.custom.68789.js"));

Resultados en;

<script src="//127.0.0.1:10000/devstoreaccount1/cdn/modernizr.js?v=g-XPguHFgwIb6tGNcnvnI_VY_ljCYf2BDp_NS5X7sAo1"></script>

Si CdnHost no está configurado, usará el Uri del blob en lugar del CDN.

Clase

using System; using System.Text; using System.Web; using System.Web.Optimization; using System.Security.Cryptography; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.ServiceRuntime; using Microsoft.WindowsAzure.StorageClient; namespace SiegeEngineWebRole.BundleExtentions { public class AzureScriptBundle : Bundle { public AzureScriptBundle(string virtualPath, string containerName, string cdnHost = "") : base(virtualPath, null, new IBundleTransform[] { new JsMinify(), new AzureBlobUpload { ContainerName = containerName, CdnHost = cdnHost } }) { ConcatenationToken = ";"; } } public class AzureStyleBundle : Bundle { public AzureStyleBundle(string virtualPath, string containerName, string cdnHost = "") : base(virtualPath, null, new IBundleTransform[] { new CssMinify(), new AzureBlobUpload { ContainerName = containerName, CdnHost = cdnHost } }) { } } public class AzureBlobUpload : IBundleTransform { public string ContainerName { get; set; } public string CdnHost { get; set; } static AzureBlobUpload() { } public virtual void Process(BundleContext context, BundleResponse response) { var file = VirtualPathUtility.GetFileName(context.BundleVirtualPath); if (!context.BundleCollection.UseCdn) { return; } if (string.IsNullOrWhiteSpace(ContainerName)) { throw new Exception("ContainerName Not Set"); } var conn = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("DataConnectionString")); var blob = conn.CreateCloudBlobClient() .GetContainerReference(ContainerName) .GetBlobReference(file); blob.Properties.ContentType = response.ContentType; blob.UploadText(response.Content); var uri = string.IsNullOrWhiteSpace(CdnHost) ? blob.Uri.AbsoluteUri.Replace("http:", "").Replace("https:", "") : string.Format("//{0}/{1}/{2}", CdnHost, ContainerName, file); using (var hashAlgorithm = CreateHashAlgorithm()) { var hash = HttpServerUtility.UrlTokenEncode(hashAlgorithm.ComputeHash(Encoding.Unicode.GetBytes(response.Content))); context.BundleCollection.GetBundleFor(context.BundleVirtualPath).CdnPath = string.Format("{0}?v={1}", uri, hash); } } private static SHA256 CreateHashAlgorithm() { if (CryptoConfig.AllowOnlyFipsAlgorithms) { return new SHA256CryptoServiceProvider(); } return new SHA256Managed(); } } }