Запуск первого приложения в Microsoft Azure. Миграция веб-сайта в Cloud Services

путь к первому приложению

    <h5 style="font-size: 18px; line-height: 20px; text-transform: uppercase; color: #239B23; padding-top: 30px;padding-bottom: 15px;font-weight: 700;font-family: 'Segoe UI', Tahoma, Arial, Helvetica, Sans-Serif; color: #1ba5d8;">Часть VI. Запуск первого приложения в Microsoft Azure. Миграция веб-сайта в Cloud Services</h5>
    <table border="0" cellpadding="1" cellspacing="2" style="font-weight: 100;font-size: 16px;font-family: 'Segoe UI Light', 'Segoe UI', Tahoma, Arial, Helvetica, Sans-Serif; color: #4c4c4c;" width="100%">
      <tr align="left" valign="top">
        <td style="padding-bottom: 20px;padding-right: 15px;">
          <p>Давайте рассмотрим следующий сценарий: вы уже развернули ваш веб-сайт (например, стандартный веб-сайт ASP.NET MVC 4, который будет дальше рассматриваться) на Microsoft Azure Web Sites, однако по прошествии некоторого времени обнаружили, что от веб-сайта требуется дополнительная функциональность – необходимо, чтобы пользователь мог заходить на ваш веб-сайт и загружать изображения в собственную галерею. Подобный сценарий реализуем с помощью одной функциональности веб-сайтов, однако в списке требований также есть условие гибкой масштабируемости вашего веб-сайта. В том случае, если вы используете только Microsoft Azure Web Sites, вы можете масштабировать ваш веб-сайт только целиком, что является неэффективным решением – скорее всего, основная нагрузка будет приходиться на обработчиков изображений, нежели на пользовательский веб-интерфейс. Миграция веб-сайта в Cloud Services и переосмысление архитектуры с учетом ролевой модели Microsoft Azure Cloud Services, а также использование Microsoft Azure Blob Storage и Service Bus Queues поможет создать эффективную реализацию подобного сценария. В данной части цикла вы создадите облачное приложение, которое будет состоять из двух слоёв:<br /></p>
          <ol>
            <li>Веб-интерфейс, реализованный в виде Web-роли. На главной странице приложения пользователь сможет загружать изображения, а также просматривать уже загруженные изображения. После загрузки изображения Web-роль будет отправлять изображение в хранилище блобов в контейнер блобов, имя которого будет заранее задано для упрощения задачи, после чего класть сообщение, состоящее из ссылки на блоб с изображением в очередь Service Bus.</li>
            <li>Обработчик изображений, реализованный в виде Worker-роли. Обработчик в бесконечном цикле будет опрашивать очередь Service Bus на наличие сообщений от Web-роли и в том случае, если сообщение в очереди есть, будет забирать его, получать ссылку на блоб с изображением, затем с помощью механизма копирования исходника-блоба создавать новый блоб с таким же изображением и класть его в хранилище блобов.</li>
          </ol>
          <h4>Настройка Cloud Services на платформе Microsoft Azure</h4>
          <p>Откройте в веб-браузере <a runat="server" href="https://windows.azure.com/">https://windows.azure.com</a> и войдите в систему, используя ваш Windows Live ID, к которому привязан аккаунт Microsoft Azure.<br /><br />Создайте новый аккаунт хранилища, в котором будут храниться данные приложения. В меню Microsoft Azure нажмите <strong>New Storage Account</strong>. В появившемся диалоговом окне <strong>Create a New Storage Account</strong> выберите в выпадающем списке <strong>Choose a subscription</strong> вашу подписку. В текстовом поле <strong>Enter a URL</strong> ввведите имя вашего аккаунта хранилища, например, <strong><em>gallery</em></strong>, где является уникальным именем. Microsoft Azure использует это значение для создания URL точек входа сервисов аккаунта хранилищ. Выберите <strong>Create or choose an affinity group</strong> и нажмите в выпадающем списке <strong>Create a new affinity group</strong>. В диалоговом окне <strong>Create a New Affinity Group</strong> введите в текстовое поле <strong>Affinity Group Name</strong> имя аффинной группы, выберите расположение (<strong>Location</strong>) в выпадающем списке и нажмите <strong>OK</strong>. Вернувшись в диалоговое окно <strong>Create a New Storage Account</strong>, нажмите <strong>Create</strong> для создания нового аккаунта хранилища.<br /><br />Дождитесь окончания процесса инициализации аккаунта и обновления «дерева» <strong>Storage Accounts</strong>. Обратите внимание, что панель свойств <strong>Properties</strong> показывает <strong>URL</strong>, ассоциированный с каждым сервисом в аккаунте хранилища. Запишите публичное имя аккаунта хранилища – первый сегмент URL ваших точек входа. Нажмите кнопку <strong>View,</strong> расположенную рядом с <strong>Primary access key</strong> в панели свойств <strong>Properties</strong>. В диалоговом окне <strong>View Storage Access Keys</strong> нажмите <strong>Copy to Clipboard</strong> (рядом с <strong>Primary Access Key)</strong>. Скопированное значение понадобится для конфигурирования приложения.<br /><br />Создайте вычислительный сервис, который будет выполнять код вашего приложения: на левой панели нажмите <strong>Hosted Services</strong> и нажмите кнопку <strong>New Hosted Service</strong>, расположенную в меню. В диалоговом окне <strong>Create a new Hosted Service</strong> выберите вашу подписку из выпадающего списка <strong>Choose a subscription</strong>. Введите имя сервиса в текстовое поле <strong>Enter a name for your service</strong> и укажите URL, введя соответствующее значение <strong>Enter a URL prefix for your service</strong>, например, <strong><em>gallery</em></strong>, где должно быть уникальным именем. Microsoft Azure использует это значение для создания URL точек входа в сервис. Выберите в выпадающем списке <strong>Create or choose an affinity group</strong> аффинную группу, которую вы создали ранее для аккаунта хранилища. Укажите <strong>Do not Deploy</strong>. Нажмите <strong>OK</strong> для создания сервиса и подождите, пока не завершится процесс инициализации. Перейдите на вкладку <strong>Service Bus, Access Control &amp; Caching.</strong> Перейдите на вкладку <strong>Service Bus.</strong> Нажмите <strong>New</strong>. В открывшемся диалоговом окне <strong>Create a new Service Namespace</strong> введите имя вашего <strong>Namespace</strong> (например, <strong>mytestservicebus</strong>), выберите регион расположения и нажмите <strong>Create Namespace... .</strong>Выделите созданное пространство имён и нажмите на кнопку <strong>View</strong> на панели <strong>Properties</strong>в поле <strong>Default Key.</strong> Скопируйте из диалогового окна <strong>Default Key</strong> значения <strong>Default Issuer</strong> и <strong>Default Key</strong>.<br /><br />Сервисы развертывания и хранения настроены; пространство имён Service Bus создано.</p>
        </td>
      </tr>
      <tr align="left" valign="top">
        <td style="padding-bottom: 20px;padding-right: 15px;">
          <h4>Настройка приложения ASP.NET MVC 4</h4>
          <p>Откройте Visual Studio 2012 с правами администратора.<br /><br />Нажмите <strong>New Project</strong>. Выберите шаблон <strong>Web\ASP.NET MVC 4 Web Application</strong> (рис. 1). Назовите проект <strong>MVC4Gallery</strong>. Выберите <strong>Internet Application</strong> и снимите галочку с опции <strong>Create a unit test project.</strong> Нажмите <strong>OK.</strong> Дождитесь создания проекта.</p>
        </td>
      </tr>
      <tr align="left" valign="top">
        <td style="padding-bottom: 20px;">
          <a runat="server" target="_blank" href="http://i.msdn.microsoft.com/jj656840.01_b(ru-ru,msdn.10).png">
            <img alt="" src="https://msdn.microsoft.com/ru-ru/jj656840.clip_image0016(ru-ru,MSDN.10).png" title="" />
          </a>
          <br />Рис. 1. Список шаблонов веб-проектов в Visual Studio 2012<br /><br />Нажмите правой кнопкой мыши на директории <strong>Models.</strong> Нажмите <strong>Add =&amp;gt; Class.</strong> В открывшемся диалоговом окне введите <strong>Image.cs</strong> и нажмите <strong>OK</strong>. Замените содержимое файла <strong>Image.cs</strong> на код, приведённый ниже.</td>
      </tr>
    </table>

    <StoCodeHighlighter runat="server" ContainsMarkup="false" HideLineNumbers="False" Language="C++">using System;

using System.Collections.Generic; using System.Linq; using System.Web;

namespace MVC4Gallery.Models { public class Image { public string Title{ get; set; } public string Link{ get; set; } }}

Откройте файл Views \ Home \ Index. cshtml и замените его содержимое на код, приведенный ниже.

    <StoCodeHighlighter runat="server" ContainsMarkup="false" HideLineNumbers="False" Language="C++">&lt;header&gt;

<div class="content-wrapper"> <div class="float-left"> <p class="site-title"> Наш первый сайт-галерея </div> </div> </header> <div id="body"> <section class="featured"> <div class="content-wrapper"> <form action="/Home/Upload" method="post" enctype="multipart/form-data"> <label for="title"> <label for="FileData"> Файл</label> <input type="file" id="FileData" name="FileData" /><br /> <input type="submit" value="Сохранить" /> </form> Ваши изображения после "обработки": @foreach (var image in ViewData.Model) { @image.Title <br /> <img width="100" height="100" src="@image.Link" /><br /> } </div> </section> </div>

Откройте файл Controllers \ HomeController. cs и замените его содержимое на код, приведенный ниже. Необходимые зависимости и библиотеки будут добавлены в следующем пункте.

    <StoCodeHighlighter runat="server" ContainsMarkup="false" HideLineNumbers="False" Language="C++">using System;

using System.Collections.Generic; using System.Collections.Specialized; using System.Web; using System.Web.Mvc; using Microsoft.ServiceBus.Messaging; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.StorageClient; using MVC4Gallery.Models;

namespace MvcApplication1.Controllers { public class HomeController : Controller {

public ActionResult Index() { List<Image> images = getBlobs("ourgallery"); return View(images); }

[HttpPost] [ActionName("Upload")] public ActionResult Upload(string author, string title) { this.SendBlobToStorage(author); return RedirectToAction("Index"); }

public void SendBlobToStorage(string author) { try { HttpPostedFileBase file = Request.Files[0]; CloudBlob blob = getBlobContainer("ourgallery"). GetBlobReference(file.FileName); NameValueCollection metadata = new NameValueCollection(); metadata["title"] = file.FileName; blob.UploadFromStream(file.InputStream); BrokeredMessage msg = new BrokeredMessage(blob.Uri.AbsoluteUri); SendBrokeredMessageToServiceBusQueue(msg); } catch (StorageClientException e) { Console.WriteLine ("Возникла ошибка во время работы с хранилищем: " + e.Message); System.Environment.Exit(1); }}

public List<Image> getBlobs(string author){

CloudBlobContainer container = getBlobContainer(author); List<Image> images = new List<Image>(); foreach (CloudBlob blob in container.ListBlobs()) { blob.FetchAttributes(); Image image = new Image(); image.Link = blob.Uri.AbsoluteUri; image.Title = blob.Metadata["title"]; images.Add(image); } return images; }

public static CloudBlobContainer getBlobContainer(string userId) { var account = CloudStorageAccount. FromConfigurationSetting("storageaccount"); CloudBlobContainer container = account.CreateCloudBlobClient(). GetContainerReference(userId); container.CreateIfNotExist(); var permissions = container.GetPermissions(); permissions.PublicAccess = BlobContainerPublicAccessType.Container; container.SetPermissions(permissions); return container; }

public static void SendBrokered MessageToServiceBusQueue(BrokeredMessage msg) { QueueDescription qd = new QueueDescription("servicebustest"); qd.MaxSizeInMegabytes = 5120; qd.DefaultMessageTimeToLive = new TimeSpan(0, 1, 0); string connectionString = CloudConfigurationManager.GetSetting ("Microsoft.ServiceBus.ConnectionString"); QueueClient Client = QueueClient.CreateFromConnectionString (connectionString, "servicebustest");

Client.Send(msg); }}}

Нажмите правой кнопкой мыши на директории References. Выберите Add Reference. В открывшемся диалоговом окне (рис. 3) выберите следующие сборки:

Microsoft.WindowsAzure.StorageClient 1.7.0.0
Microsoft.WindowsAzure.Configuration 1.7.0.0
Microsoft.WindowsAzure.ServiceRuntime 1.7.0.0
Microsoft.ServiceBus 1.7.0.0
System.Runtime.Serialization 4.0.0.0


Рис. 3. Выбор сборок для проекта.

Откройте файл Global. asax и добавьте в метод Application_Start () код, приведённый ниже.

    <StoCodeHighlighter runat="server" ContainsMarkup="false" HideLineNumbers="False" Language="C++">CloudStorageAccount.

SetConfigurationSetting Publisher((configName, configSettingPublisher) => { var connectionString = RoleEnvironment. GetConfigurationSettingValue(configName); configSettingPublisher(connectionString); });

Щелкните правой кнопкой мыши на проекте. Выберите Add Microsoft Azure Cloud Service Project (рис. 4).


Рис. 4. Добавление облачного проекта в решение

Нажмите правой кнопкой мыши на Roles в созданном проекте MVC 4 Gallery. Azure. Выберите Add. Нажмите New Worker Role Project (рис. 5).


Рис. 5. Добавление проекта для Worker-роли в решение

В Microsoft Azure Tools 1.7 был добавлен новый шаблон Worker-роли, уже сконфигурированный для использования Service Bus. В окне Add New Role Project выберите Worker Role with Service Bus Queue и нажмите Add (рис. 6).


Рис. 6. Добавление проекта Worker-роли, сконфигурированного для использования Service Bus Queue

Откройте файл WorkerRole.cs и замените его содержимое на код, приведённый ниже.

    <StoCodeHighlighter runat="server" ContainsMarkup="false" HideLineNumbers="False" Language="C++">using System;

using System.Collections.Specialized; using System.Diagnostics; using System.Net; using System.Threading; using Microsoft.ServiceBus; using Microsoft.ServiceBus.Messaging; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.ServiceRuntime; using Microsoft.WindowsAzure.StorageClient;

namespace WorkerRoleWithSBQueue1 {

public class WorkerRole : RoleEntryPoint

{ // The name of your queue const string QueueName = "servicebustest"; // QueueClient is thread-safe. Recommended that you cache // rather than recreating it on every request QueueClient Client; bool IsStopped;

public override void Run() { while (!IsStopped) { try { // Получение сообщения BrokeredMessage receivedMessage = null; receivedMessage = Client.Receive(); if (receivedMessage != null) { // Обработка сообщения. В данном случае изображение получается из блоба, затем возвращается в том же виде, но с другим именем файла. GetBlobFromStorage("ourgallery", receivedMessage.GetBody<string>()); receivedMessage.Complete(); }} catch (MessagingException e) { if (!e.IsTransient) { Trace.WriteLine(e.Message); throw; } Thread.Sleep(10000); } catch (OperationCanceledException e) { if (!IsStopped) { Trace.WriteLine(e.Message); throw; }}}}

public override bool OnStart() { CloudStorageAccount.SetConfiguration SettingPublisher((configName, configSettingPublisher) => { var connectionString = RoleEnvironment. GetConfigurationSettingValue(configName); configSettingPublisher(connectionString); });

// Определение максимального количества одновременных подключений ServicePointManager.DefaultConnectionLimit = 12;

// Создание очереди в том случае, если ее еще не существует string sbconnectionString = CloudConfigurationManager. GetSetting("Microsoft.ServiceBus.ConnectionString"); var namespaceManager = NamespaceManager. CreateFromConnectionString(sbconnectionString); if (!namespaceManager.QueueExists(QueueName)) { namespaceManager.CreateQueue(QueueName); }

// Инициализация подключения к очереди Service Bus Client = QueueClient.Create FromConnectionString(sbconnectionString, QueueName); IsStopped = false; return base.OnStart(); }

public override void OnStop() { // Закрытие подключения к очереди Service Bus IsStopped = true; Client.Close(); base.OnStop(); }

public void GetBlobFromStorage(string author, string title) { try { CloudBlob sourceBlob = getBlobContainer("ourgallery").GetBlobReference(title); CloudBlob newBlob = getBlobContainer("ourgallery"). GetBlobReference(title + "small_copy"); newBlob.CopyFromBlob(sourceBlob); NameValueCollection metadata = new NameValueCollection(); metadata["title"] = title + "small_copy"; } catch (StorageClientException e) { Console.WriteLine("Возникла ошибка: " + e.Message); System.Environment.Exit(1); }}

public static CloudBlobContainer getBlobContainer(string userId) { var account = CloudStorageAccount .FromConfigurationSetting("storageaccount"); CloudBlobContainer container = account. CreateCloudBlobClient().GetContainerReference(userId); container.CreateIfNotExist(); return container; }}}

Добавьте в проект MVC4Gallery файл WebRole.cs и замените его содержимое на код, приведённый ниже.

    <StoCodeHighlighter runat="server" ContainsMarkup="false" HideLineNumbers="False" Language="C++">using System;

using System.Collections.Generic; using System.Linq; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.Diagnostics; using Microsoft.WindowsAzure.ServiceRuntime; using Microsoft.WindowsAzure.StorageClient;

namespace MVC4Gallery { public class WebRole : RoleEntryPoint {

public override bool OnStart() { RoleEnvironment.Changing += RoleEnvironmentChanging; return base.OnStart(); }

private void RoleEnvironment Changing(object sender, RoleEnvironmentChangingEventArgs e) { if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange)) { e.Cancel = true; }}}}

Нажмите два раза правой кнопкой мыши на MVC 4 Gallery в Roles облачного проекта для того, чтобы открыть графический интерфейс администрирования Web-роли (рис. 7).


Рис. 7. Графический интерфейс управления Web-ролью

На вкладке Configuration снимите отметку с опции Enable Diagnostics. Перейдите на вкладку Settings, нажмите Add Setting и создайте новую настройку конфигурации с именем storageaccount. Укажите её тип как Connection String, после чего нажмите на кнопку с троеточием и настройте строку подключения. Необходимые данные были записан в Части 1. Нажмите Add Setting и введите имя Microsoft.ServiceBus.ConnectionString (тип – String), после чего вставьте в поле Value следующую строку:

Endpoint=sb://[имяпространстваимён].servicebus.windows.net;SharedSecretIssuer=
owner;SharedSecretValue=[DefaultKey]

Где наименование пространства имён для части Endpoint, Default Issuer для SharedSecretIssuer и Default Key для SharedSecretValue. Нажмите OK. Нажмите два раза правойкнопкой мыши на WorkerRoleWithSBQueue 1 в Roles облачного проекта для того, чтобы открыть графический интерфейс администрирования Worker-роли.

На вкладке Configuration снимите отметку с опции Enable Diagnostics. Перейдите на вкладку Settings, нажмите Add Setting и создайте новую настройку конфигурации сименем storageaccount. Укажите её тип как Connection String, после чего нажмите на кнопку с троеточием и настройте строку подключения. Необходимые данные были записаны в Части 1. Нажмите OK. Вставьте необходимые значения в строку подключения для настройки Microsoft.ServiceBus.ConnectionString. Необходимые данные были записаны в Части 1 – наименование пространства имён для части Endpoint, Default Issuer для SharedSecretIssuer и Default Keyдля SharedSecretValue. Сохраните изменения и закройте графический интерфейс управления Worker-ролью.

Запустите проект, нажав F5. Проект запустится в локальном эмуляторе вычислений и запустит браузер с представлением Home / Index .

Выберите изображение и нажмите Сохранить. После загрузки изображения страница обновится. Обратите внимание, что в данный момент показывается только одно изображение – то, которое вы загрузили. Спустя некоторое время (достаточно нескольких секунд) обновите страницу – это время понадобится обработчику изображений, чтобы опросить очередь, получить сообщение от Web-роли, загрузить блоб, создать его копию и положить новый блоб в хранилище.

Развертывание ASP.NET MVC 4 приложения на платформу Microsoft Azure в Cloud Services из Visual Studio 2012

Для того, чтобы развернуть приложение в Cloud Services на платформу Microsoft Azure, необходимо соответствующим образом настроить функциональность публикации в Visual Studio 2012

Нажмите правой кнопкой мыши на облачном проекте MVC 4 Gallery. Azure. Нажмите Publish. В открывшемся диалоговом окне раскройте список под Choose your subscription и выберите < Manage …> (рис. 12).


Рис. 12.

В открывшемся диалоговом окне Microsoft Azure Cloud Service Project Management нажмите New. Введите любое удобное вам название нового сертификата, который будет использоваться для развертывания приложения. Нажмите Ok Нажмите на ссылку Copy the full path. Перейдите на портал управления Microsoft Azure. Перейдите на вкладку Hosted Services, Storage Accounts & CDN... Перейдите на вкладку Management Certificates... На вкладку Management Certificates нажмите Add Certificate. В открывшемся диалоговом окне Add New Management Certificate нажмите Browse и вставьте в поле Имя файла скопированный из Visual Studio путь к сертификату. Нажмите Открыть. Нажмите Ok. Перейдите на вкладку Hosted Services и скопируйте Subscription ID из панели Properties. Перейдите в Visual Studio 2012. Вставьте скопированный идентификатор подписки в соответствующее поле (рис. 13). Нажмите OK.


Рис. 13.

Нажмите Close. Нажмите Next . На странице Microsoft Azure Publish Settings вы можете настроить дополнительные опции развертывания. Нажмите Publish. Вы можете наблюдать за процессом развёртывания в представлении Microsoft Azure Activity Log (рис. 14).


Рис. 14. Представление Microsoft Azure Activity Log

Перейдите на портал управления Microsoft Azure на вкладку Hosted Services. Выберите развернутое приложение и нажмите на ссылку в поле DNS Name на панели Properties, чтобы перейти на веб-сайт (рис. 15).


Рис. 15. Портал управления Microsoft Azure

Обратите внимание, что сайт выглядит так же, как после развёртывания его в локальный эмулятор вычислений. Это связано с тем, что в обоих случаях используется реальное хранилище Microsoft Azure. Добавьте новое изображение и пронаблюдайте результат.

Автор статьи: Александр Белоцерковский, Microsoft Azure MVP.

следующий шаг