Integrare un servizio cloud con la rete CDN di AzureIntegrate a cloud service with Azure CDN

È possibile integrare un servizio cloud con la rete CDN di Azure, rendendo disponibile qualsiasi contenuto dalla posizione del servizio cloud.A cloud service can be integrated with Azure CDN, serving any content from the cloud service's location. Questo approccio offre i vantaggi seguenti:This approach gives you the following advantages:

  • Facile distribuzione e aggiornamento di immagini, script e fogli di stile nelle directory del progetto servizio cloudEasily deploy and update images, scripts, and stylesheets in your cloud service's project directories
  • Facile aggiornamento dei pacchetti NuGet nel servizio cloud, come le versioni jQuery o BootstrapEasily upgrade the NuGet packages in your cloud service, such as jQuery or Bootstrap versions
  • Gestione dell'applicazione Web e del contenuto gestito dalla rete CDN dalla stessa interfaccia di Visual StudioManage your Web application and your CDN-served content all from the same Visual Studio interface
  • Flusso di lavoro di distribuzione unificato per l'applicazione Web e il contenuto gestito dalla rete CDNUnified deployment workflow for your Web application and your CDN-served content
  • Integrazione di creazione di bundle e minimizzazione ASP.NET con la rete CDN di AzureIntegrate ASP.NET bundling and minification with Azure CDN

Contenuto dell'esercitazioneWhat you will learn

In questa esercitazione si apprenderà come:In this tutorial, you will learn how to:

Obiettivo di compilazioneWhat you will build

Verrà distribuito un ruolo Web del servizio cloud usando il modello MVC di ASP.NET predefinito, si aggiungerà il codice per gestire il contenuto da una rete CDN di Azure integrata, ad esempio un'immagine, i risultati dell'azione del controller e i file JavaScript e CSS predefiniti, e si scriverà anche il codice per configurare il meccanismo di fallback per i bundle serviti nel caso in cui la rete CDN non sia in linea.You will deploy a cloud service Web role using the default ASP.NET MVC template, add code to serve content from an integrated Azure CDN, such as an image, controller action results, and the default JavaScript and CSS files, and also write code to configure the fallback mechanism for bundles served in the event that the CDN is offline.

PrerequisitiWhat you will need

Per completare questa esercitazione, è necessario disporre dei prerequisiti seguenti:This tutorial has the following prerequisites:

Nota

Per completare l'esercitazione, è necessario un account Azure.You need an Azure account to complete this tutorial:

  • È possibile aprire un account Azure gratuitamente: si riceveranno dei crediti da usare per provare i servizi di Azure a pagamento e, anche dopo avere esaurito i crediti, è possibile mantenere l'account per usare i servizi di Azure gratuiti, ad esempio Siti Web.You can open an Azure account for free - You get credits you can use to try out paid Azure services, and even after they're used up you can keep the account and use free Azure services, such as Websites.
  • È possibile attivare i benefici della sottoscrizione MSDN: con la sottoscrizione MSDN ogni mese si accumulano crediti che è possibile usare per i servizi di Azure a pagamento.You can activate MSDN subscriber benefits - Your MSDN subscription gives you credits every month that you can use for paid Azure services.

Distribuire un servizio cloudDeploy a cloud service

In questa sezione verrà distribuito il modello di applicazione MVC di ASP.NET predefinito in Visual Studio 2015 a un ruolo Web del servizio cloud, che verrà quindi integrato con un nuovo endpoint CDN.In this section, you will deploy the default ASP.NET MVC application template in Visual Studio 2015 to a cloud service Web role, and then integrate it with a new CDN endpoint. Seguire le istruzioni riportate di seguito:Follow the instructions below:

  1. In Visual Studio 2015 creare un nuovo servizio cloud di Azure dalla barra dei menu File > Nuovo > Progetto > Cloud > Servizio cloud di Azure.In Visual Studio 2015, create a new Azure cloud service from the menu bar by going to File > New > Project > Cloud > Azure Cloud Service. Assegnargli un nome e fare clic su OK.Give it a name and click OK.

  2. Selezionare Ruolo Web ASP.NET e fare clic sul pulsante >.Select ASP.NET Web Role and click the > button. Fare clic su OK.Click OK.

  3. Selezionare MVC e fare clic su OK.Select MVC and click OK.

  4. Pubblicare ora questo ruolo Web in un servizio cloud di Azure.Now, publish this Web role to an Azure cloud service. Fare clic con il pulsante destro del mouse sul progetto servizio cloud e selezionare Pubblica.Right-click the cloud service project and select Publish.

  5. Se non è stata ancora effettuato l’accesso a Microsoft Azure, fare clic su Aggiungi un account nell'elenco a discesa e fare clic sulla voce di menu Aggiungi un account.If you have not yet signed into Microsoft Azure, click the Add an account... dropdown and click the Add an account menu item.

  6. Nella pagina di accesso eseguire l'accesso con l'account Microsoft usato per attivare l'account Azure.In the sign-in page, sign in with the Microsoft account you used to activate your Azure account.
  7. Una volta effettuato l'accesso, fare clic su Avanti.Once you're signed in, click Next.

  8. Supponendo che non sia stato creato un servizio cloud né un account di archiviazione, Visual Studio aiuterà a crearli entrambi.Assuming that you haven't created a cloud service or storage account, Visual Studio will help you create both. Nella finestra di dialogo Crea servizio cloud e account di archiviazione , digitare il nome del servizio desiderato e selezionare l’area desiderata.In the Create Cloud Service and Account dialog, type the desired service name and select the desired region. Fare quindi clic su Crea.Then, click Create.

  9. Nella pagina Impostazioni di pubblicazione, verificare la configurazione e fare clic su Pubblica.In the publish settings page, verify the configuration and click Publish.

    Nota

    Il processo di pubblicazione per i servizi cloud richiede tempi elevati.The publishing process for cloud services takes a long time. L'opzione Abilita Distribuzione Web per tutti i ruoli Web può velocizzare il debug del servizio cloud fornendo aggiornamenti rapidi (ma temporanei) dei ruoli Web.The Enable Web Deploy for all roles option can make debugging your cloud service much quicker by providing fast (but temporary) updates to your Web roles. Per altre informazioni su questa opzione, vedere Pubblicazione di un servizio cloud con gli strumenti di Azure.For more information on this option, see Publishing a Cloud Service using the Azure Tools.

    Quando la finestra Log attività di Microsoft Azure indica che lo stato di pubblicazione è Completato, è possibile creare un endpoint della rete CDN integrato con il servizio cloud.When the Microsoft Azure Activity Log shows that publishing status is Completed, you will create a CDN endpoint that's integrated with this cloud service.

    Avviso

    Se, dopo la pubblicazione, il servizio cloud distribuito mostra una schermata di errore, probabilmente è perché il servizio cloud che è stato distribuito usa un guest del sistema operativo che non include .NET 4.5.2.If, after publishing, the deployed cloud service displays an error screen, it's likely because the cloud service you've deployed is using a guest OS that does not include .NET 4.5.2. È possibile risolvere il problema da distribuzione .NET 4.5.2 come attività di avvio.You can work around this issue by deploying .NET 4.5.2 as a startup task.

Creare un nuovo profilo di rete CDNCreate a new CDN profile

Un profilo di rete CDN è una raccolta di endpoint della rete CDN.A CDN profile is a collection of CDN endpoints. Ogni profilo contiene uno o più endpoint della rete CDN.Each profile contains one or more CDN endpoints. Si consiglia di usare più profili per organizzare gli endpoint della rete CDN tramite il dominio internet, l’applicazione web o altri criteri.You may wish to use multiple profiles to organize your CDN endpoints by internet domain, web application, or some other criteria.

Suggerimento

Se si dispone già di un profilo di rete CDN che si desidera usare per questa esercitazione, passare a Creare un nuovo endpoint della rete CDN.If you already have a CDN profile that you want to use for this tutorial, proceed to Create a new CDN endpoint.

Per creare un nuovo profilo di rete CDNTo create a new CDN profile

  1. Nel portale di Azurefare clic su Nuovoin alto a sinistra.In the Azure Portal, in the upper left, click New. Nel pannello Nuovo selezionare Web e dispositivi mobili e quindi Rete CDN.In the New blade, select Web + Mobile, then CDN.

    Viene visualizzato il pannello del nuovo profilo di rete CDN.The new CDN profile blade appears.

    Nuovo profilo di rete CDN

  2. Inserire un nome per il profilo di rete CDN.Enter a name for your CDN profile.
  3. Selezionare un percorso.Select a Location. Questo è il percorso di Azure in cui verranno archiviate le informazioni relative al profilo di rete CDN.This is the Azure location where your CDN profile information will be stored. Non incide sulle posizioni dell’endpoint di rete CDN.It has no impact on CDN endpoint locations.
  4. Selezionare o creare un gruppo di risorse.Select or create a Resource Group. Per altre informazioni sui gruppi di risorse, vedere Panoramica di Azure Resource Manager.For more information on Resource Groups, see Azure Resource Manager overview.
  5. Selezionare un Piano tariffario.Select a Pricing tier. Per un confronto tra i piani tariffari, vedere Panoramica della rete CDN .See the CDN Overview for a comparison of pricing tiers.

    Selezione del piano tariffario della rete CDN

  6. Selezionare la Sottoscrizione per questo profilo di rete CDN.Select the Subscription for this CDN profile.
  7. Per creare il nuovo profilo, fare clic sul pulsante Crea .Click the Create button to create the new profile.

Creare un nuovo endpoint della rete CDNCreate a new CDN endpoint

Per creare un nuovo endpoint della rete CDN per l'account di archiviazioneTo create a new CDN endpoint for your storage account

  1. Nel portale di gestione di Azurepassare al profilo di rete CDN.In the Azure Management Portal, navigate to your CDN profile. Lo si potrebbe aver bloccato nel dashboard nel passaggio precedente.You may have pinned it to the dashboard in the previous step. Se così non fosse, è possibile trovarlo facendo clic su Esplora, quindi su Profili rete CDN e facendo clic sul profilo in cui si prevede di aggiungere l'endpoint.If you not, you can find it by clicking Browse, then CDN profiles, and clicking on the profile you plan to add your endpoint to.

    Viene visualizzato il pannello del profilo di rete CDN.The CDN profile blade appears.

    Profilo di rete CDN

  2. Fare clic sul pulsante Aggiungi Endpoint .Click the Add Endpoint button.

    Pulsante Aggiungi endpoint

    Viene visualizzato il pannello Aggiungi un endpoint .The Add an endpoint blade appears.

    Pannello Aggiungi endpoint

  3. Immettere un Nome per questo endpoint della rete CDN.Enter a Name for this CDN endpoint. Questo nome verrà usato per accedere alle risorse memorizzate nella cache nel dominio <EndpointName>.azureedge.net.This name will be used to access your cached resources at the domain <EndpointName>.azureedge.net.
  4. Nell'elenco a discesa Tipo di origine , selezionare Servizio cloud.In the Origin type dropdown, select Cloud service.
  5. Nell'elenco a discesa Nome host di origine , selezionare il servizio cloud.In the Origin hostname dropdown, select your cloud service.
  6. Lasciare le impostazioni predefinite per Percorso dell'origine, Intestazione host di origine e Protocollo/Porta dell'origine.Leave the defaults for Origin path, Origin host header, and Protocol/Origin port. È necessario specificare almeno un protocollo (HTTP o HTTPS).You must specify at least one protocol (HTTP or HTTPS).
  7. Per creare il nuovo endpoint, fare clic sul pulsante Aggiungi .Click the Add button to create the new endpoint.
  8. Dopo la creazione, l'endpoint sarà visualizzato in un elenco di endpoint per il profilo.Once the endpoint is created, it appears in a list of endpoints for the profile. Nella visualizzazione elenco sono mostrati gli URL da usare per accedere a contenuti memorizzati nella cache, oltre al dominio di origine.The list view shows the URL to use to access cached content, as well as the origin domain.

    Endpoint della rete CDN

    Nota

    L'endpoint non sarà immediatamente disponibile per l'uso.The endpoint will not immediately be available for use. Ci possono volere fino a 90 minuti per far sì che la registrazione si propaghi attraverso la rete CDN.It can take up to 90 minutes for the registration to propagate through the CDN network. È possibile che gli utenti che provano a usare immediatamente il nome di dominio della rete CDN ricevano un errore con codice di stato 404 fino a quando il contenuto non risulterà disponibile tramite la rete CDN.Users who try to use the CDN domain name immediately may receive status code 404 until the content is available via the CDN.

Testare l'endpoint della rete CDNTest the CDN endpoint

Quando lo stato di pubblicazione è Completato, aprire una finestra del browser e passare a http://*.azureedge.net/Content/bootstrap.css.When the publishing status is Completed, open a browser window and navigate to http://*.azureedge.net/Content/bootstrap.css. Nella configurazione illustrata, questo URL è il seguente:In my setup, this URL is:

http://camservice.azureedge.net/Content/bootstrap.css

che corrisponde all'URL di origine seguente all'endpoint della rete CDN:Which corresponds to the following origin URL at the CDN endpoint:

http://camcdnservice.cloudapp.net/Content/bootstrap.css

Quando si passa a http://<cdnName>.azureedge.net/Content/bootstrap.css, a seconda del browser, verrà richiesto di scaricare o di aprire il file bootstrap.css disponibile nell'app Web pubblicata.When you navigate to http://<cdnName>.azureedge.net/Content/bootstrap.css, depending on your browser, you will be prompted to download or open the bootstrap.css that came from your published Web app.

È possibile accedere in maniera simile a qualsiasi URL pubblicamente accessibile all'indirizzo http://<nomeServizio>.cloudapp.net/, direttamente dall'endpoint della rete CDN.You can similarly access any publicly accessible URL at http://<serviceName>.cloudapp.net/, straight from your CDN endpoint. ad esempio:For example:

  • Un file con estensione js dal percorso /ScriptA .js file from the /Script path
  • Qualsiasi file di contenuto dal percorso /ContentAny content file from the /Content path
  • Qualsiasi controller/azioneAny controller/action
  • Se la stringa di query viene abilitata sull'endpoint della rete CDN, qualsiasi URL con stringhe di queryIf the query string is enabled at your CDN endpoint, any URL with query strings

In effetti, con la configurazione precedente, è possibile ospitare l'intero servizio cloud da http://<cdnName>.azureedge.net/.In fact, with the above configuration, you can host the entire cloud service from http://<cdnName>.azureedge.net/. Se si passa a http://camservice.azureedge.net/, si ottiene il risultato dell'azione da Home/Index.If I navigate to http://camservice.azureedge.net/, I get the action result from Home/Index.

Ciò non significa, ad ogni modo, che sia sempre una buona idea rendere disponibile un intero servizio cloud attraverso la rete CDN di Azure.This does not mean, however, that it's always a good idea to serve an entire cloud service through Azure CDN.

Una rete CDN con ottimizzazione della distribuzione statica non velocizza necessariamente la distribuzione degli asset dinamici, che non sono progettati per la memorizzazione nella cache o che vengono aggiornati molto spesso, poiché la rete CDN deve eseguire molto spesso il pull di una nuova versione dell'asset dal server di origine.A CDN with static delivery optimization does not necessarily speed up delivery of dynamic assets which are not meant to be cached, or are updated very frequently, since the CDN must pull a new version of the asset from the Origin server very often. Per questo scenario è possibile abilitare l'ottimizzazione Accelerazione sito dinamico nell'endpoint di rete CDN che usa diverse tecniche per velocizzare la distribuzione di asset dinamici non memorizzabili nella cache.For this scenario, you can enable Dynamic Site Acceleration optimization (DSA) on your CDN endpoint which uses various techniques to speed up delivery of non-cacheable dynamic assets.

Se è presente un sito con una combinazione di contenuto statico e dinamico, è possibile scegliere di fornire il contenuto statico dalla rete CDN con un tipo di ottimizzazione statica, ad esempio la distribuzione generale sul Web, e di fornire il contenuto dinamico direttamente dal server di origine oppure tramite un endpoint di rete CDN con l'ottimizzazione Accelerazione sito dinamico attivata in base al caso specifico.If you have a site with a mix of static and dynamic content, you can choose to serve your static content from CDN with a static optimization type (such as general web delivery), and to serve dynamic content either directly from the origin server, or through a CDN endpoint with DSA optimization turned on a case-by-case basis. A tale scopo, si è già visto come accedere ai singoli file di contenuto dall'endpoint della rete CDN.To that end, you have already seen how to access individual content files from the CDN endpoint. Più avanti, in Gestire il contenuto dalle azioni del controller attraverso la rete CDN di Azure, verrà illustrato come gestire una specifica azione del controller attraverso l'endpoint di rete CDN.I will show you how to serve a specific controller action through a specific CDN endpoint in Serve content from controller actions through Azure CDN.

L'alternativa consiste nel determinare quale contenuto rendere disponibile dalla rete CDN di Azure, valutando caso per caso nel servizio cloud.The alternative is to determine which content to serve from Azure CDN on a case-by-case basis in your cloud service. A tale scopo, si è già visto come accedere ai singoli file di contenuto dall'endpoint della rete CDN.To that end, you have already seen how to access individual content files from the CDN endpoint. Più avanti verrà illustrato come gestire una specifica azione del controller attraverso l'endpoint CDN in Gestire il contenuto dalle azioni del controller attraverso la rete CDN di Azure.I will show you how to serve a specific controller action through the CDN endpoint in Serve content from controller actions through Azure CDN.

Configurare le opzioni di memorizzazione nella cache dei file statici nel servizio cloudConfigure caching options for static files in your cloud service

Con l'integrazione della rete CDN di Azure nel servizio cloud è possibile specificare in che modo si vuole memorizzare il contenuto statico nella cache dell'endpoint della rete CDN.With Azure CDN integration in your cloud service, you can specify how you want static content to be cached in the CDN endpoint. A tale scopo, aprire il file Web.config dal progetto di ruolo Web (ad esempio, WebRole1) e aggiungere un elemento <staticContent> a <system.webServer>.To do this, open Web.config from your Web role project (e.g. WebRole1) and add a <staticContent> element to <system.webServer>. Il linguaggio XML seguente configura la scadenza della cache entro tre giorni.The XML below configures the cache to expire in 3 days.

<system.webServer>
  <staticContent>
    <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="3.00:00:00"/>
  </staticContent>
  ...
</system.webServer>

A questo punto, tutti i file statici nel servizio cloud osserveranno la stessa regola nella cache della rete CDN.Once you do this, all static files in your cloud service will observe the same rule in your CDN cache. Per un controllo più granulare delle impostazioni della cache, aggiungere un file Web.config in una cartella e quindi aggiungervi le impostazioni.For more granular control of cache settings, add a Web.config file into a folder and add your settings there. Ad esempio, aggiungere un file Web.config alla cartella \Content e sostituire il contenuto con il seguente codice XML:For example, add a Web.config file to the \Content folder and replace the content with the following XML:

<?xml version="1.0"?>
<configuration>
  <system.webServer>
    <staticContent>
      <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="15.00:00:00"/>
    </staticContent>
  </system.webServer>
</configuration>

Queste impostazioni causano la memorizzazione nella cache di tutti i file statici della cartella \Content per 15 giorni.This setting causes all static files from the \Content folder to be cached for 15 days.

Per altre informazioni su come configurare l'elemento <clientCache>, vedere Client Cache <clientCache> (Cache client).For more information on how to configure the <clientCache> element, see Client Cache <clientCache>.

Nella sezione Gestire il contenuto dalle azioni del controller attraverso la rete CDN di Azureverrà illustrato anche come configurare le impostazioni della cache per ottenere i risultati dell'azione del controller nella cache della rete CDN.In Serve content from controller actions through Azure CDN, I will also show you how you can configure cache settings for controller action results in the CDN cache.

Gestire il contenuto dalle azioni del controller attraverso la rete CDN di AzureServe content from controller actions through Azure CDN

Quando si integra un ruolo Web del servizio cloud nella rete CDN di Azure, è relativamente facile gestire il contenuto dalle azioni del controller attraverso la rete CDN di Azure.When you integrate a cloud service Web role with Azure CDN, it is relatively easy to serve content from controller actions through the Azure CDN. Invece di rendere disponibile il servizio cloud direttamente attraverso la rete CDN (come descritto sopra), Maarten Balliauw mostra come farlo con un divertente controller MemeGenerator nel video sulla riduzione della latenza sul Web con la rete CDN di Azure,Other than serving your cloud service directly through Azure CDN (demonstrated above), Maarten Balliauw shows you how to do it with a fun MemeGenerator controller in Reducing latency on the web with the Azure CDN. che viene riprodotto semplicemente in questo articolo.I will simply reproduce it here.

Si supponga di volere generare nel servizio cloud dei meme basati su un'immagine di un giovane Chuck Norris (foto di Alan Light), come questa:Suppose in your cloud service you want to generate memes based on a young Chuck Norris image (photo by Alan Light) like this:

Si usa una semplice azione Index che consente ai clienti di specificare i superlativi nell'immagine, quindi genera il meme dopo aver pubblicato nell'azione.You have a simple Index action that allows the customers to specify the superlatives in the image, then generates the meme once they post to the action. Poiché si tratta di Chuck Norris, ci si aspetta che questa pagina diventi enormemente popolare in tutto il mondo.Since it's Chuck Norris, you would expect this page to become wildly popular globally. È un ottimo esempio di come gestire contenuto semi dinamico con la rete CDN di Azure.This is a good example of serving semi-dynamic content with Azure CDN.

Seguire i passaggi precedenti per configurare questa azione del controller:Follow the steps above to setup this controller action:

  1. Nella cartella \Controllers creare un nuovo file con estensione cs denominato MemeGeneratorController.cs e sostituire il contenuto con il codice seguente.In the \Controllers folder, create a new .cs file called MemeGeneratorController.cs and replace the content with the following code. Assicurarsi di sostituire la parte evidenziata con il nome della propria rete CDN.Be sure to replace the highlighted portion with your CDN name.

     using System;
     using System.Collections.Generic;
     using System.Diagnostics;
     using System.Drawing;
     using System.IO;
     using System.Net;
     using System.Web.Hosting;
     using System.Web.Mvc;
     using System.Web.UI;
    
     namespace WebRole1.Controllers
     {
         public class MemeGeneratorController : Controller
         {
             static readonly Dictionary<string, Tuple<string ,string>> Memes = new Dictionary<string, Tuple<string, string>>();
    
             public ActionResult Index()
             {
                 return View();
             }
    
             [HttpPost, ActionName("Index")]
             public ActionResult Index_Post(string top, string bottom)
             {
                 var identifier = Guid.NewGuid().ToString();
                 if (!Memes.ContainsKey(identifier))
                 {
                     Memes.Add(identifier, new Tuple<string, string>(top, bottom));
                 }
    
                 return Content("<a href=\"" + Url.Action("Show", new {id = identifier}) + "\">here's your meme</a>");
             }
    
             [OutputCache(VaryByParam = "*", Duration = 1, Location = OutputCacheLocation.Downstream)]
             public ActionResult Show(string id)
             {
                 Tuple<string, string> data = null;
                 if (!Memes.TryGetValue(id, out data))
                 {
                     return new HttpStatusCodeResult(HttpStatusCode.NotFound);
                 }
    
                 if (Debugger.IsAttached) // Preserve the debug experience
                 {
                     return Redirect(string.Format("/MemeGenerator/Generate?top={0}&bottom={1}", data.Item1, data.Item2));
                 }
                 else // Get content from Azure CDN
                 {
                     return Redirect(string.Format("http://<yourCdnName>.azureedge.net/MemeGenerator/Generate?top={0}&bottom={1}", data.Item1, data.Item2));
                 }
             }
    
             [OutputCache(VaryByParam = "*", Duration = 3600, Location = OutputCacheLocation.Downstream)]
             public ActionResult Generate(string top, string bottom)
             {
                 string imageFilePath = HostingEnvironment.MapPath("~/Content/chuck.bmp");
                 Bitmap bitmap = (Bitmap)Image.FromFile(imageFilePath);
    
                 using (Graphics graphics = Graphics.FromImage(bitmap))
                 {
                     SizeF size = new SizeF();
                     using (Font arialFont = FindBestFitFont(bitmap, graphics, top.ToUpperInvariant(), new Font("Arial Narrow", 100), out size))
                     {
                         graphics.DrawString(top.ToUpperInvariant(), arialFont, Brushes.White, new PointF(((bitmap.Width - size.Width) / 2), 10f));
                     }
                     using (Font arialFont = FindBestFitFont(bitmap, graphics, bottom.ToUpperInvariant(), new Font("Arial Narrow", 100), out size))
                     {
                         graphics.DrawString(bottom.ToUpperInvariant(), arialFont, Brushes.White, new PointF(((bitmap.Width - size.Width) / 2), bitmap.Height - 10f - arialFont.Height));
                     }
                 }
    
                 MemoryStream ms = new MemoryStream();
                 bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
                 return File(ms.ToArray(), "image/png");
             }
    
             private Font FindBestFitFont(Image i, Graphics g, String text, Font font, out SizeF size)
             {
                 // Compute actual size, shrink if needed
                 while (true)
                 {
                     size = g.MeasureString(text, font);
    
                     // It fits, back out
                     if (size.Height < i.Height &&
                          size.Width < i.Width) { return font; }
    
                     // Try a smaller font (90% of old size)
                     Font oldFont = font;
                     font = new Font(font.Name, (float)(font.Size * .9), font.Style);
                     oldFont.Dispose();
                 }
             }
         }
     }
    
  2. Fare clic con il pulsante destro del mouse sull'azione Index() predefinita e selezionare Aggiungi visualizzazione.Right-click in the default Index() action and select Add View.

  3. Accettare le impostazioni di seguito e fare clic su Aggiungi.Accept the settings below and click Add.

  4. Aprire il nuovo file Views\MemeGenerator\Index.cshtml e sostituire il contenuto con il semplice HTML seguente per inviare i superlativi:Open the new Views\MemeGenerator\Index.cshtml and replace the content with the following simple HTML for submitting the superlatives:

     <h2>Meme Generator</h2>
    
     <form action="" method="post">
         <input type="text" name="top" placeholder="Enter top text here" />
         <br />
         <input type="text" name="bottom" placeholder="Enter bottom text here" />
         <br />
         <input class="btn" type="submit" value="Generate meme" />
     </form>
    
  5. Pubblicare nuovamente il servizio cloud e passare a http://<serviceName>.cloudapp.net/MemeGenerator/Index nel browser.Publish the cloud service again and navigate to http://<serviceName>.cloudapp.net/MemeGenerator/Index in your browser.

Quando si inviano i valori del modulo a /MemeGenerator/Index, il metodo di azione Index_Post restituisce un collegamento al metodo di azione Show con il rispettivo identificatore di input.When you submit the form values to /MemeGenerator/Index, the Index_Post action method returns a link to the Show action method with the respective input identifier. Facendo clic sul collegamento si raggiunge il codice seguente:When you click the link, you reach the following code:

[OutputCache(VaryByParam = "*", Duration = 1, Location = OutputCacheLocation.Downstream)]
public ActionResult Show(string id)
{
    Tuple<string, string> data = null;
    if (!Memes.TryGetValue(id, out data))
    {
        return new HttpStatusCodeResult(HttpStatusCode.NotFound);
    }

    if (Debugger.IsAttached) // Preserve the debug experience
    {
        return Redirect(string.Format("/MemeGenerator/Generate?top={0}&bottom={1}", data.Item1, data.Item2));
    }
    else // Get content from Azure CDN
    {
        return Redirect(string.Format("http://<yourCDNName>.azureedge.net/MemeGenerator/Generate?top={0}&bottom={1}", data.Item1, data.Item2));
    }
}

Se il debugger locale è collegato, si avrà una normale esperienza di debug con un reindirizzamento locale.If your local debugger is attached, then you will get the regular debug experience with a local redirect. Se viene eseguito nel servizio cloud, si verrà reindirizzati a:If it's running in the cloud service, then it will redirect to:

http://<yourCDNName>.azureedge.net/MemeGenerator/Generate?top=<formInput>&bottom=<formInput>

che corrisponde all'URL di origine seguente in corrispondenza dell'endpoint della rete CDN:Which corresponds to the following origin URL at your CDN endpoint:

http://<youCloudServiceName>.cloudapp.net/MemeGenerator/Generate?top=<formInput>&bottom=<formInput>

Sarà quindi possibile usare l'attributo OutputCacheAttribute sul metodo Generate per specificare come memorizzare nella cache il risultato dell'azione, che verrà rispettato dalla rete CDN di Azure.You can then use the OutputCacheAttribute attribute on the Generate method to specify how the action result should be cached, which Azure CDN will honor. Il codice seguente specifica la scadenza di una cache entro un'ora (3.600 secondi).The code below specify a cache expiration of 1 hour (3,600 seconds).

[OutputCache(VaryByParam = "*", Duration = 3600, Location = OutputCacheLocation.Downstream)]

Analogamente, è possibile rendere disponibile il contenuto da qualsiasi azione del controller nel servizio cloud attraverso la rete CDN di Azure, con l'opzione di memorizzazione nella cache desiderata.Likewise, you can serve up content from any controller action in your cloud service through your Azure CDN, with the desired caching option.

Nella sezione successiva verrà illustrato come gestire gli script e i file CSS in bundle e minimizzati attraverso la rete CDN di Azure.In the next section, I will show you how to serve the bundled and minified scripts and CSS through Azure CDN.

Integrazione di creazione di bundle e minimizzazione ASP.NET con la rete CDN di AzureIntegrate ASP.NET bundling and minification with Azure CDN

Gli script e i fogli di stile CSS cambiano in maniera non frequente e sono i principali candidati per la cache della rete CDN di Azure.Scripts and CSS stylesheets change infrequently and are prime candidates for the Azure CDN cache. Il modo più semplice per integrare la creazione di bundle e la minimizzazione con la rete CDN di Azure consiste nel rendere disponibile l'intero ruolo Web.Serving the entire Web role through your Azure CDN is the easiest way to integrate bundling and minification with Azure CDN. Tuttavia, poiché potrebbe non essere auspicabile, verrà illustrato come procedere pur mantenendo l'esperienza desiderata dallo sviluppatore per quanto riguarda la creazione di bundle e la minimizzazione ASP.NET, ad esempio:However, as you may not want to do this, I will show you how to do it while preserving the desired develper experience of ASP.NET bundling and minification, such as:

  • Ottima esperienza della modalità di debugGreat debug mode experience
  • Distribuzione semplificataStreamlined deployment
  • Aggiornamenti immediati delle versioni di script/css dei clientImmediate updates to clients for script/CSS version upgrades
  • Meccanismo di fallback in caso di errore dell'endpoint della rete CDNFallback mechanism when your CDN endpoint fails
  • Riduzione delle modifiche del codiceMinimize code modification

Nel progetto WebRole1 creato nella sezione dedicata all'integrazione di un endpoint della rete CDN di Azure con il sito Web di Azure e alla pubblicazione di contenuto statico nelle pagine Web di CDN di Azure aprire App_Start\BundleConfig.cs e osservare le chiamate del metodo bundles.Add().In the WebRole1 project that you created in Integrate an Azure CDN endpoint with your Azure website and serve static content in your Web pages from Azure CDN, open App_Start\BundleConfig.cs and take a look at the bundles.Add() method calls.

public static void RegisterBundles(BundleCollection bundles)
{
    bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                "~/Scripts/jquery-{version}.js"));
    ...
}

La prima istruzione bundles.Add() aggiunge un'aggregazione di script alla directory virtuale ~/bundles/jquery.The first bundles.Add() statement adds a script bundle at the virtual directory ~/bundles/jquery. Aprire quindi Views\Shared_Layout.cshtml per verificare come viene eseguito il rendering del bundle di script.Then, open Views\Shared_Layout.cshtml to see how the script bundle tag is rendered. Dovrebbe essere possibile trovare la riga di codice Razor seguente:You should be able to find the following line of Razor code:

@Scripts.Render("~/bundles/jquery")

Quando questo codice Razor viene eseguito nel ruolo Web di Azure, eseguirà il rendering di un tag <script> per il bundle di script in modo simile al seguente:When this Razor code is run in the Azure Web role, it will render a <script> tag for the script bundle similar to the following:

<script src="/bundles/jquery?v=FVs3ACwOLIVInrAl5sdzR2jrCDmVOWFbZMY6g6Q0ulE1"></script>

Tuttavia, quando il codice viene eseguito in Visual Studio digitando F5, comporta il rendering individuale di ogni file di script nell'aggregazione (nel caso sopra citato, l'aggregazione contiene un solo file di script):However, when it is run in Visual Studio by typing F5, it will render each script file in the bundle individually (in the case above, only one script file is in the bundle):

<script src="/Scripts/jquery-1.10.2.js"></script>

Ciò consente di eseguire il debug del codice JavaScript nell'ambiente di sviluppo e allo stesso tempo di ridurre le connessioni client simultanee (creazione di bundle) e migliorare le prestazioni di download dei file (minimizzazione) in produzione.This enables you to debug the JavaScript code in your development environment while reducing concurrent client connections (bundling) and improving file download performance (minification) in production. È un'ottima funzionalità da mantenere con l'integrazione nella rete CDN di Azure.It's a great feature to preserve with Azure CDN integration. Per di più, dal momento che il bundle di cui è stato eseguito il rendering contiene una stringa di versione generata automaticamente, è opportuno replicare tale funzionalità in modo che ogni volta che si aggiorna la versione di jQuery attraverso NuGet è possibile aggiornarla sul lato client non appena possibile.Furthermore, since the rendered bundle already contains an automatically generated version string, you want to replicate that functionality so the whenever you update your jQuery version through NuGet, it can be updated at the client side as soon as possible.

Attenersi alla procedura seguente per integrare la creazione di bundle e la minimizzazione ASP.NET con l'endpoint della rete CDN.Follow the steps below to integration ASP.NET bundling and minification with your CDN endpoint.

  1. Tornando ad App_Start\BundleConfig.cs, modificare i metodi bundles.Add() in modo da usare un costruttore di aggregazioni diverso, che specifichi un indirizzo di rete CDN.Back in App_Start\BundleConfig.cs, modify the bundles.Add() methods to use a different Bundle constructor, one that specifies a CDN address. A questo scopo, sostituire la definizione del metodo RegisterBundles con il codice seguente:To do this, replace the RegisterBundles method definition with the following code:

     public static void RegisterBundles(BundleCollection bundles)
     {
         bundles.UseCdn = true;
         var version = System.Reflection.Assembly.GetAssembly(typeof(Controllers.HomeController))
             .GetName().Version.ToString();
         var cdnUrl = "http://<yourCDNName>.azureedge.net/{0}?v=" + version;
    
         bundles.Add(new ScriptBundle("~/bundles/jquery", string.Format(cdnUrl, "bundles/jquery")).Include(
                     "~/Scripts/jquery-{version}.js"));
    
         bundles.Add(new ScriptBundle("~/bundles/jqueryval", string.Format(cdnUrl, "bundles/jqueryval")).Include(
                     "~/Scripts/jquery.validate*"));
    
         // Use the development version of Modernizr to develop with and learn from. Then, when you're
         // ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
         bundles.Add(new ScriptBundle("~/bundles/modernizr", string.Format(cdnUrl, "bundles/modernizer")).Include(
                     "~/Scripts/modernizr-*"));
    
         bundles.Add(new ScriptBundle("~/bundles/bootstrap", string.Format(cdnUrl, "bundles/bootstrap")).Include(
                     "~/Scripts/bootstrap.js",
                     "~/Scripts/respond.js"));
    
         bundles.Add(new StyleBundle("~/Content/css", string.Format(cdnUrl, "Content/css")).Include(
                     "~/Content/bootstrap.css",
                     "~/Content/site.css"));
     }
    

    Assicurarsi di sostituire <yourCDNName> con il nome della rete CDN.Be sure to replace <yourCDNName> with the name of your Azure CDN.

    In altri termini, si imposta bundles.UseCdn = true e si aggiunge un URL della rete CDN definito con precisione a ogni aggregazione.In plain words, you are setting bundles.UseCdn = true and added a carefully crafted CDN URL to each bundle. Ad esempio, il primo costruttore nel codice:For example, the first constructor in the code:

     new ScriptBundle("~/bundles/jquery", string.Format(cdnUrl, "bundles/jquery"))
    

    è lo stesso di:is the same as:

     new ScriptBundle("~/bundles/jquery", string.Format(cdnUrl, "http://<yourCDNName>.azureedge.net/bundles/jquery?v=<W.X.Y.Z>"))
    

    Questo costruttore comunica alle operazioni di creazione di bundle e minimizzazione ASP.NET di eseguire il rendering dei singoli file di script quando ne viene eseguito il debug a livello locale, ma di usare l'indirizzo della rete CDN specificato per accedere allo script in questione.This constructor tells ASP.NET bundling and minification to render individual script files when debugged locally, but use the specified CDN address to access the script in question. Notare tuttavia due importanti caratteristiche di questo URL della rete CDN definito con precisione:However, note two important characteristics with this carefully crafted CDN URL:

    • L'origine per questo URL della rete CDN è http://<yourCloudService>.cloudapp.net/bundles/jquery?v=<W.X.Y.Z>, che in realtà è la directory virtuale del bundle di script nel servizio cloud.The origin for this CDN URL is http://<yourCloudService>.cloudapp.net/bundles/jquery?v=<W.X.Y.Z>, which is actually the virtual directory of the script bundle in your cloud service.
    • Poiché si sta usando un costruttore CDN, il tag dello script CDN per il bundle non contiene più la stringa di versione generata automaticamente nell'URL di cui è stato eseguito il rendering.Since you are using CDN constructor, the CDN script tag for the bundle no longer contains the automatically generated version string in the rendered URL. È necessario generare manualmente una stringa di versione univoca ogni volta che il bundle di script viene modificato per forzare un mancato riscontro nella cache nella rete CDN di Azure.You must manually generate a unique version string every time the script bundle is modified to force a cache miss at your Azure CDN. Allo stesso tempo, questa stringa di versione univoca deve rimanere costante per tutta la durata della distribuzione per aumentare i riscontri nella cache nella rete CDN di Azure dopo aver distribuito il bundle.At the same time, this unique version string must remain constant through the life of the deployment to maximize cache hits at your Azure CDN after the bundle is deployed.
    • La stringa di query v=<W.X.Y.Z> effettua il pull da Properties\AssemblyInfo.cs nel progetto di ruolo Web.The query string v=<W.X.Y.Z> pulls from Properties\AssemblyInfo.cs in your Web role project. È possibile prevedere un flusso di lavoro di distribuzione che includa l'incremento della versione di assembly ogni volta che si pubblica su Azure.You can have a deployment workflow that includes incrementing the assembly version every time you publish to Azure. In alternativa, è possibile modificare solo il file Properties\AssemblyInfo.cs nel progetto per incrementare automaticamente la stringa di versione ogni volta che si compila, usando il carattere jolly ''.Or, you can just modify *Properties\AssemblyInfo.cs in your project to automatically increment the version string every time you build, using the wildcard character '*'. ad esempio:For example:

      [assembly: AssemblyVersion("1.0.0.")][assembly: AssemblyVersion("1.0.0.")]

      Qualsiasi altra strategia volta a semplificare la generazione di una stringa univoca per la durata della distribuzione avrà esito positivo.Any other strategy to streamline generating a unique string for the life of a deployment will work here.

  2. Ripubblicare il servizio cloud e accedere alla home page.Republish the cloud service and access the home page.
  3. Visualizzare il codice HTML relativo alla pagina.View the HTML code for the page. Dovrebbe essere possibile visualizzare l'URL della rete CDN di cui è stato eseguito il rendering, con una stringa di versione univoca ogni volta che si ripubblicano le modifiche al servizio cloud,You should be able to see the CDN URL rendered, with a unique version string every time you republish changes to your cloud service. Ad esempio:For example:

     ...
    
     <link href="http://camservice.azureedge.net/Content/css?v=1.0.0.25449" rel="stylesheet"/>
    
     <script src="http://camservice.azureedge.net/bundles/modernizer?v=1.0.0.25449"></script>
    
     ...
    
     <script src="http://camservice.azureedge.net/bundles/jquery?v=1.0.0.25449"></script>
    
     <script src="http://camservice.azureedge.net/bundles/bootstrap?v=1.0.0.25449"></script>
    
     ...
    
  4. In Visual Studio eseguire il debug del servizio cloud digitando F5.In Visual Studio, debug the cloud service in Visual Studio by typing F5.,
  5. Visualizzare il codice HTML relativo alla pagina.View the HTML code for the page. Sarà ancora possibile visualizzare ciascun file di script di cui sia stato eseguito il rendering, in modo che l'esperienza di debug sia coerente in Visual Studio.You will still see each script file individually rendered so that you can have a consistent debug experience in Visual Studio.

     ...
    
         <link href="/Content/bootstrap.css" rel="stylesheet"/>
     <link href="/Content/site.css" rel="stylesheet"/>
    
         <script src="/Scripts/modernizr-2.6.2.js"></script>
    
     ...
    
         <script src="/Scripts/jquery-1.10.2.js"></script>
    
         <script src="/Scripts/bootstrap.js"></script>
     <script src="/Scripts/respond.js"></script>
    
     ...   
    

Meccanismo di fallback per gli URL della rete CDNFallback mechanism for CDN URLs

Se si verifica un errore nell'endpoint della rete CDN di Azure per un motivo qualsiasi, è consigliabile configurare l'accesso della pagina Web al server Web di origine come opzione di fallback per il caricamento di JavaScript o Bootstrap.When your Azure CDN endpoint fails for any reason, you want your Web page to be smart enough to access your origin Web server as the fallback option for loading JavaScript or Bootstrap. Un conto è perdere le immagini nel sito a causa della mancata disponibilità della rete CDN, un altro è perdere funzionalità essenziali della pagina fornite dagli script e dai fogli di stile.It's serious enough to lose images on your website due to CDN unavailability, but much more severe to lose crucial page functionality provided by your scripts and stylesheets.

La classe Bundle contiene una proprietà denominata CdnFallbackExpression che consente di configurare il meccanismo di fallback per l'errore della rete CDN.The Bundle class contains a property called CdnFallbackExpression that enables you to configure the fallback mechanism for CDN failure. Per usare questa proprietà, seguire i passaggi descritti di seguito:To use this property, follow the steps below:

  1. Nel progetto di ruolo Web, aprire App_Start\BundleConfig.cs, a cui è stato aggiunto un URL della rete CDN a ogni costruttore di bundle e apportare le modifiche evidenziate di seguito per aggiungere il meccanismo di fallback ai bundle predefiniti:In your Web role project, open App_Start\BundleConfig.cs, where you added a CDN URL in each Bundle constructor, and make the following highlighted changes to add fallback mechanism to the default bundles:

     public static void RegisterBundles(BundleCollection bundles)
     {
         var version = System.Reflection.Assembly.GetAssembly(typeof(BundleConfig))
             .GetName().Version.ToString();
         var cdnUrl = "http://cdnurl.azureedge.net/.../{0}?" + version;
         bundles.UseCdn = true;
    
         bundles.Add(new ScriptBundle("~/bundles/jquery", string.Format(cdnUrl, "bundles/jquery"))
                     { CdnFallbackExpression = "window.jquery" }
                     .Include("~/Scripts/jquery-{version}.js"));
    
         bundles.Add(new ScriptBundle("~/bundles/jqueryval", string.Format(cdnUrl, "bundles/jqueryval"))
                     { CdnFallbackExpression = "$.validator" }
                     .Include("~/Scripts/jquery.validate*"));
    
         // Use the development version of Modernizr to develop with and learn from. Then, when you&#39;re
         // ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
         bundles.Add(new ScriptBundle("~/bundles/modernizr", string.Format(cdnUrl, "bundles/modernizer"))
                     { CdnFallbackExpression = "window.Modernizr" }
                     .Include("~/Scripts/modernizr-*"));
    
         bundles.Add(new ScriptBundle("~/bundles/bootstrap", string.Format(cdnUrl, "bundles/bootstrap"))     
                     { CdnFallbackExpression = "$.fn.modal" }
                     .Include(
                               "~/Scripts/bootstrap.js",
                               "~/Scripts/respond.js"));
    
         bundles.Add(new StyleBundle("~/Content/css", string.Format(cdnUrl, "Content/css")).Include(
                     "~/Content/bootstrap.css",
                     "~/Content/site.css"));
     }
    

    Quando CdnFallbackExpression non è Null, lo script viene inserito nel linguaggio HTML per provare se l'aggregazione è stata caricata correttamente. In caso contrario, accedere all'aggregazione direttamente dal server Web dell'origine.When CdnFallbackExpression is not null, script is injected into the HTML to test whether the bundle is loaded successfully and, if not, access the bundle directly from the origin Web server. Questa proprietà deve essere impostata su un'espressione JavaScript che verifichi se il rispettivo bundle CDN è stato caricato correttamente.This property needs to be set to a JavaScript expression that tests whether the respective CDN bundle is loaded properly. L'espressione necessaria per testare ogni bundle differisce in base al contenuto.The expression needed to test each bundle differs according to the content. Per i bundle predefiniti sopra riportati:For the default bundles above:

    • window.jquery viene definito nel file jquery-{version}.jswindow.jquery is defined in jquery-{version}.js
    • $.validator viene definito nel file jquery.validate.js$.validator is defined in jquery.validate.js
    • window.Modernizr viene definito nel file modernizer-{version}.jswindow.Modernizr is defined in modernizer-{version}.js
    • $.fn.modal viene definito nel file bootstrap.js$.fn.modal is defined in bootstrap.js

      Come è possibile osservare, non è stata impostata la proprietà CdnFallbackExpression per l'aggregazione ~/Cointent/css,You might have noticed that I did not set CdnFallbackExpression for the ~/Cointent/css bundle. perché attualmente esiste un bug in System.Web.Optimization che inserisce un tag <script> per il file CSS di fallback invece del tag <link> previsto.This is because currently there is a bug in System.Web.Optimization that injects a <script> tag for the fallback CSS instead of the expected <link> tag.

      Un'ottima soluzione di Fallback Style Bundle è tuttavia offerta da Ember Consulting Group.There is, however, a good Style Bundle Fallback offered by Ember Consulting Group.

  2. Per usare la soluzione alternativa per CSS, creare un nuovo file .cs nella cartella App_Start del progetto di ruolo Web, denominato StyleBundleExtensions.cs e sostituirne il contenuto con il codice di GitHub.To use the workaround for CSS, create a new .cs file in your Web role project's App_Start folder called StyleBundleExtensions.cs, and replace its content with the code from GitHub.
  3. Nel file App_Start\StyleFundleExtensions.cs, rinominare lo spazio dei nomi con il nome del proprio ruolo Web (ad esempio WebRole1).In App_Start\StyleFundleExtensions.cs, rename the namespace to your Web role's name (e.g. WebRole1).
  4. Tornare a App_Start\BundleConfig.cs e modificare l’ultima istruzione bundles.Add con il seguente codice evidenziato:Go back to App_Start\BundleConfig.cs and modify the last bundles.Add statement with the following highlighted code:

     bundles.Add(new StyleBundle("~/Content/css", string.Format(cdnUrl, "Content/css"))
         <mark>.IncludeFallback("~/Content/css", "sr-only", "width", "1px")</mark>
         .Include(
               "~/Content/bootstrap.css",
               "~/Content/site.css"));
    

    Questo nuovo metodo di estensione si basa sulla stessa idea di inserire lo script nel linguaggio HTML per cercare in DOM il nome di classe, il nome di regola e il valore di regola corrispondenti definiti nel bundle CSS, eseguendo il fallback sul server Web in caso non riesca a trovare la corrispondenza.This new extension method uses the same idea to inject script in the HTML to check the DOM for the a matching class name, rule name, and rule value defined in the CSS bundle, and falls back to the origin Web server if it fails to find the match.

  5. Pubblicare di nuovo il servizio cloud e accedere alla home page.Publish the cloud service again and access the home page.
  6. Visualizzare il codice HTML relativo alla pagina.View the HTML code for the page. Gli script inseriti dovrebbero essere simili al seguente:You should find injected scripts similar to the following:

     ...
    
     <link href="http://az632148.azureedge.net/Content/css?v=1.0.0.25474" rel="stylesheet"/>
     <script>(function() {
                     var loadFallback,
                         len = document.styleSheets.length;
                     for (var i = 0; i < len; i++) {
                         var sheet = document.styleSheets[i];
                         if (sheet.href.indexOf('http://camservice.azureedge.net/Content/css?v=1.0.0.25474') !== -1) {
                             var meta = document.createElement('meta');
                             meta.className = 'sr-only';
                             document.head.appendChild(meta);
                             var value = window.getComputedStyle(meta).getPropertyValue('width');
                             document.head.removeChild(meta);
                             if (value !== '1px') {
                                 document.write('<link href="/Content/css" rel="stylesheet" type="text/css" />');
                             }
                         }
                     }
                     return true;
                 }())||document.write('<script src="/Content/css"><\/script>');</script>
    
         <script src="http://camservice.azureedge.net/bundles/modernizer?v=1.0.0.25474"></script>
     <script>(window.Modernizr)||document.write('<script src="/bundles/modernizr"><\/script>');</script>
    
     ...
    
         <script src="http://camservice.azureedge.net/bundles/jquery?v=1.0.0.25474"></script>
     <script>(window.jquery)||document.write('<script src="/bundles/jquery"><\/script>');</script>
    
         <script src="http://camservice.azureedge.net/bundles/bootstrap?v=1.0.0.25474"></script>
     <script>($.fn.modal)||document.write('<script src="/bundles/bootstrap"><\/script>');</script>
    
     ...
    

    Si noti che lo script inserito per l'aggregazione CSS contiene ancora residui della proprietà CdnFallbackExpression nella riga:Note that injected script for the CSS bundle still contains the errant remnant from the CdnFallbackExpression property in the line:

     }())||document.write('<script src="/Content/css"><\/script>');</script>
    

    Poiché però la prima parte dell'espressione || restituirà sempre true (nella riga subito sopra), la funzione document.write() non verrà mai eseguita.But since the first part of the || expression will always return true (in the line directly above that), the document.write() function will never run.

Altre informazioniMore Information