Цель данной лекции – ознакомиться с технологиями Microsoft .NET Services.
.NET Services предоставляет основные стандартные блоки, которые понадобятся при построении приложений в облаке и работающих с облаком для Azure™ Services Platform.
Сервисы, собранные под именем .NET Services, обеспечивают инфраструктуру облака, которая, в конечном счете, упрощает построение работающих в облаке приложений.
Сегодня .NET Services обеспечивают основную функциональность, связанную с возможностями подключения приложений, управления доступом и взаимодействия посредством сообщений на базе рабочего процесса. Со временем они будут предоставлять больший набор функций и среду на базе облака. На данный момент под именем .NET Services объединены следующие основные блоки сервисов:
Данные новые сервисы можно рассматривать как .NET-инфраструктуру сервисов для облака. Все они доступны через открытые протоколы и стандарты, включая REST, SOAP, Atom/AtomPub и WS. Это означает, что разработчики на любой платформе могут интегрироваться с этими сервисами.
Однако, в попытке сделать все максимально привычным для .NET-разработчиков, Microsoft также предоставляет .NET Services SDK, который обеспечивает первоклассные условия для .NET-разработчика и скрывает многие сложные моменты работы с сервисами.
.NET Services SDK позволяет разработчикам использовать имеющийся опыт .NET-разработки, в частности в областях WCF и WF, через применение новых расширений инфраструктуры SDK (например, новых привязок, каналов и действия). SDK также включает поддержку инструментов Visual Studio для интеграции с порталом Azure™ Services Portal. Кроме .NET Services SDK, сегодня партнеры Microsoft предлагают Java и Ruby SDK (ссылки можно найти в разделе " Дополнительные ресурсы ").
Чтобы начать работу с .NET Services, перейдите на портал Azure™ Services Platform по адресу http://azure.com и щелкните ссылку "Try It Now" (Попробуйте сейчас). Вы перейдете на страницу " Register for Azure Services " (Регистрация для сервисов Azure), представленную на рисунке 8.1. На этой странице даются важные ссылки для скачивания различных SDK, доступа к дополнительным ресурсам и перехода на сайт Microsoft Connect, где можно зарегистрироваться для получения кода приглашения.
(рис 8.1) Портал Azure™ Services Platform
Далее потребуется загрузить .NET Services SDK. Обратите внимание, что имеется несколько SDK: один – специально предназначенный для разработки Windows® Azure™; другой – для разработки .NET Services; и остальные – для SQL Data Services и Live Framework. Для воспроизведения примеров, предлагаемых в данной серии документов, понадобится скачать и установить .NET Services SDK.
Скачав .NET Services SDK, просто запустите программу установки, как показано на рисунке 8.2. Тем самым вам будут доступны новые .NET-сборки, которые вместе с некоторыми надстройками Visual Studio помогут начать использование различных функций .NET Services. Приступая к работе с .NET Services, обязательно ознакомьтесь с остальными ресурсами, доступными с этой страницы (демонстрации, видео, практические лабораторные и т.д.), цель которых – сделать процесс обучения более насыщенным и разнообразным. Скачать SDK можно, не создавая учетной записи, но, чтобы использовать сервисы, необходимо зарегистрироваться.
(рис 8.2) Запуск установки NET Services SDK
Чтобы зарегистрироваться на получения учетной записи Azure Services, щелкните показанную выше ссылку " Register for Services " (Регистрация для сервисов). Вам будет предложено зарегистрироваться, используя Windows Live ID (WLID). После этого вы перейдете на сайт Microsoft Connect, где потребуется заполнить регистрационную форму Azure Services
(рис 8.3) Регистрация для Azure Services Platform на сайте Microsoft Connect
Теперь можно вернуться на страницу входа .NET Services Эту страницу можно увидеть на рисунке 8.4.
(рис 8.4) Страница входа .NET Services
Теперь, щелкнув " Sign Up " (Войти), вы получаете возможность создавать решение .NET Services. Примечание: в
Для создания решения необходимо просто ввести уникальное имя решения, принять условия использования и нажать " Create Solution " (Создать решение). После этого новое решение будет подготовлено и ассоциировано с вашим WLID. Теперь, в любой момент, зарегистрировавшись на портале Azure™ Services Platform, вы имеете возможность управлять решениями, ассоциированными с вашим WLID.
Имя решения должно быть не менее 6 символов длиной и глобально уникальным среди всех пользователей .NET-сервисов. Возможно, придется проявить смекалку, чтобы придумать такое имя для решения, которое еще не используется никем другим.
После того, как новое решение создано, на экран выводится страница (рисунок 8.5), предлагающая пароль решения, который желательно сохранить для использования в будущем. Имя решения и пароль выступают в роли учетных данных для доступа к различным сервисам .NET Services.
(рис 8.5) Завершение процесса подготовки решения
После успешного создания решения можно приступать к работе с ним на портале Azure™ Services Platform. Зарегистрировавшись под собственным WLID, на странице портала справа вы увидите меню " My Solutions " (Мои решения) (рисунок 8.6). Для работы с конкретным решением необходимо просто выбрать его в меню " My Solutions ", после чего вам будет представлена страница, показанная на рисунке 8.7.
По сути, решение – это контейнер верхнего уровня для организации различных ресурсов .NET Services.Например, в нем размещаются конечные точки .NET Service Bus, типы и экземпляры рабочих процессов .NET Workflow Service, а также ваши удостоверения .NET Access Control Service и правила преобразования утверждений. Но одним из самых важных аспектов, которым вы захотите управлять после создания собственного решения, являются учетные данные решения.
Именно поэтому имя решения должно быть уникальным среди всех пользователей.
(рис 8.6) Управление своими решениями посредством меню "My Solutions"
(рис 8.7) Управление отдельным решением
Пароль решения, предоставленный в процессе подготовки, можно изменить на странице " Credential Management " (Управление учетными данными) (просто щелкните ссылку " Solution Credentials " (Учетные данные решения), которую можно видеть на рис. 8.8). С этой страницы можно также конфигурировать информационные карточки
(рис 8.8) Управление учетными данными своего решения
Для
Самым распространенным требованием в распределенных приложениях с высоким уровнем масштабируемости является возможность подключения приложений. Обычно интеграция приложений – одна из самых дорогостоящих и хлопотных областей ИТ. Сегодня для этих задач многие организации используют решение Enterprise Service Bus. Enterprise Service Bus (сервисная шина предприятия, ESB) — подход к построению распределённых корпоративных информационных систем. Обычно включает в себя промежуточное ПО, которое обеспечивает взаимосвязь между различными приложениями по различным протоколам взаимодействия.
Архитектура
Одним из стандартов взаимодействия являются веб-сервисы. В популярных реализациях
NET Service Bus является основной частью предложения .NET Services. Ее основная задача – сделать шаблон
Internet Service Bus позволила бы интегрировать ваш локальный
Чтобы это стало реальностью, реализация должна обеспечивать интегрированные решения, основанные на открытых Интернет-стандартах, и насыщенную среду обмена сообщениями с возможностью двусторонней связи в Интернет.
(рис 8.9) Сервисная шина Интернет
Реализация двусторонней связи в Интернете не такая уж тривиальная задача из-за некоторых реалий организации современных сетей. Преимущественно, барьеры в сети создают межсетевые экраны и устройства, работающие по протоколу NAT, которые усложняют обмен информацией с узлами, располагающимися за ними. Представьте ситуацию: торговый агент использует ваше приложение по беспроводной сети в случайной гостинице в некоторой точке земного шара. Как при таком сценарии определить его местоположение и инициировать связь?
Часто компании решают эти проблемы связи, открывая входящие порты межсетевых экранов (что доставляет немало хлопот системным администраторам) или используя различных обходные приемы, такие как динамическая DNS, сопоставление портов NAT или технологию
Network address translation – Преобразование сетевых адресов.
Domain Name System – Служба доменных имен.
Universal Plug and Play – Универсальная автоматическая настройка сетевых устройств.
Решение идентификации, реализацией которой Microsoft занимается последние несколько лет, основано на концепции утверждений. Модель идентификации на базе утверждений позволяет выносить общие функции аутентификации и авторизации из приложений и осуществлять их централизованно во внешних сервисах, написанных и обслуживаемых экспертами безопасности и идентификации, что выгодно всем, кто участвует в этом процессе.
Microsoft® .NET Access Control Service – это сервис в облаке, выполняющий именно эту функцию. Вместо того чтобы создавать собственную базу данных пользовательских учетных записей и ролей, можно предоставить возможность .NET Access Control Service управлять аутентификацией и авторизацией ваших пользователей. .NET Access Control Service использует существующие хранилища учетных записей пользователей, такие как Windows Live ID и Active Directory, а также любые другие хранилища, поддерживающие стандартные протоколы интегрирования. Таким образом, использование единой регистрации для доступа ко всем приложениям становится вполне естественным. Также это обеспечивает централизацию логики аутентификации и управления доступом, что упрощает ваши приложения.
В поддерживающих утверждения приложениях пользователь представляет свое удостоверение как набор утверждений. Одним утверждением может быть имя пользователя; другим – его адрес электронной почты. Эти утверждения предоставляются организацией, выдающей удостоверения, которая знает, как аутентифицировать пользователя и где найти его атрибуты. Клиентское приложение, в роли которого может выступать браузер или насыщенный клиент, напрямую получает утверждения от этой организации и передает их в ваше приложение (рисунок 8.10).
(рис 8.10) Использование идентификации на базе утверждений для веб-сервисов
В итоге, приложение получает все сведения, необходимые для идентификации пользователя, в виде набора утверждений. Эти утверждения подписываются, что обеспечивает криптографическое подтверждение их происхождения.
Модель идентификации на базе утверждений упрощает реализацию единой регистрации, при этом приложение больше не отвечает ни за один из перечисленных ниже аспектов безопасности:
Используя такую модель, приложение может принимать решения об идентификации на основании предоставленных пользователем утверждений. И диапазон таких решений велик: от простой персонализации приложения по имени пользователя до авторизации пользователя для доступа к особо важным функциям и ресурсам приложения.
.NET Access Control Service реализовывает идентификацию на базе утверждений в рамках платформы Azure™ Services Platform. Система администрирования является важной частью .NET Access Control Service.
(рис 8.11) Портал ACS
.NET Access Control Service предоставляет портал администрирования (рисунок 8.11) в рамках портала Azure™ Services Portal. Здесь вы выполняете настройку правил, которые определяют схему выпуска утверждений для различных пользователей.
Портал Access Control Service – замечательное средство для исследования, изучения и начала работы с
Сервис .NET Access Control Service также включает конечные точки SOAP и REST для программного администрирования, а также ряд .NET-классов,
которые упрощают вызов этих конечных точек. Итак, если вам не нравится портал, предоставляемый
Самой большой проблемой в построении крупномасштабных распределенных приложений является принятие решения о моделировании сложных схем взаимодействия через обмен сообщениями. Microsoft .NET Workflow Service позволяет разрабатывать логику взаимодействия сообщений с помощью WF и обеспечивает размещенную масштабируемую среду для выполнения и управления экземплярами рабочего процесса WF в облаке, освобождая разработчика от необходимости создания собственного хоста для WF.
.NET Workflow Service является частью Azure™ Services Platform и интегрируется с сервисами .NET Service Bus и .NET Access Control Service для безопасного координирования взаимодействия посредством сообщений. .NET Workflow Service также обеспечивает инструменты управления для создания и управления типами и экземплярами рабочих потоков и API веб-сервисов для ситуаций, когда требуется создать собственные инструменты.
Поскольку управляющая среда построена на платформе Windows® Azure™, она может масштабироваться по требованию и в значительной степени, при этом организации или разработчику не приходится беспокоиться о планировании большего количества оборудования или программного обеспечения. Благодаря использованию среды выполнения WF экземпляры рабочего потока могут выполняться в
На период перехода к обработке данных в облаке .NET Workflow Services предоставляет упрощенный подход для управления сложными взаимодействиями .NET Service Bus в создаваемых вами составных решениях "в облаке".
Построение хоста для рабочих процессов WF означает принятие решений о том, какие возможности будет поддерживать среда и как лучше сделать ее безопасной, масштабируемой и стабильной. Сегодня .NET Workflow Service построен на .NET Framework 3.5 и действиях и компонентах WF, входящих в данную версию инфраструктуры. Однако для обеспечения наилучших условий Microsoft были добавлены несколько специальных действий и сервисов, которые наложили некоторые ограничения на рабочие процессы, выполняющиеся в облаке.
В облаке не используется сервис хранения SqlWorkflowPersistenceProvider, получивший наибольшую популярность среди разработчиков, применяющих WF. Чтобы использовать операционную среду Azure и обеспечить наилучшие возможности масштабирования и стабильности, в инфраструктуре облака имеется специальный провайдер услуг хранения, который реализует сохранение состояния выполняющихся рабочих процессов посредством возможностей хранения Microsoft SQL Services. Кроме всего прочего, для Интернет-сервиса необходима Интернет-технология хранения и извлечения данных. Но поскольку механизм WF един – как в облаке, так и в ваших локальных решениях, – применение специального провайдера услуг хранения прозрачно для разработчиков рабочих процессов. Все делается так же, как в любой другое среде WF.
При построении рабочих процессов для облака разработчики используют привычные инструменты Visual Studio, включая тот же дизайнер рабочего процесса для создания XAML-файлов рабочих процессов и файлов правил. Затем эти XML-файлы загружаются на сервер в облаке, где они могут использоваться для создания экземпляров рабочего процесса. .NET Services SDK включает шаблон проекта для создания SequentialCloudWorkflow (Последовательный рабочий процесс в облаке), который является специальной версией стандартного шаблона SequentialWorkflow (Последовательный рабочий процесс). Одним из ограничений текущей инфраструктуры является то, что при определении рабочих процессов, которые будут выполняться в облаке, можно использовать только подмножество действий базовой библиотеки действий, а также комплект специальных действий, предоставляемый как часть .NET Services SDK.
Набор действий требует, чтобы рабочие процессы были полностью декларативными и ограничивающими. Это предотвращает введение пользовательского кода, т.е. позволяет гарантировать стабильность среды. При построении управляющей среды для рабочих процессов, написанных любым количеством разработчиков, разбросанных по всему миру, такой уровень контроля является обязательным. Поскольку сегодня для выполнения WF необходимо полное доверие, мы не можем обеспечить ограниченный набор функциональности, просто выделив пользовательский код в безопасную изолированную программную среду на серверах. Следует отметить, что со временем доступный сегодня ограниченный набор действий будет расширен для увеличения возможностей рабочего процесса в облаке. По мере выхода новых версий .NET Framework и .NET Workflow Service также будет поддерживать их. Кроме того, если понадобятся специальные этапы, возможности локальных рабочих процессов могут комбинироваться с рабочими процессами в облаке с помощью .NET Service Bus.
.NET Services SDK содержит новый шаблон проекта для построения рабочих процессов в облаке, набором новых действий в облаке и клиентским API для удаленного развертывания и управления рабочими процессами, размещаемыми в облаке.
При написании рабочих процессов в облаке необходимо быть аккуратным с используемыми действиями (дизайнер предложит только допустимые действия). Разрешенными являются некоторые основные действия потока управления WF, включая IfElse (Если…то), While (Пока), Sequence (Последовательность), Suspend (Приостановить), Terminate (Завершить) и FaultHandler (Обработчик сбоев). Кроме базовых действий потока управления, в рабочих процесса в облаке могут также использоваться CancellationHandlerActivity и FaultHandlersActivity для моделирования обработки исключений и логики отмены. Обратите внимание, что эти действия обычно не добавляются в модель напрямую; для этого используется дизайнер составных действий, который вводит их автоматически, когда представление переходит к этому действию.
Ни одно другое действие WF или пользовательские действия не могут использоваться. Разрешены к применению только новые специальные действия в облаке, включенные в .NET Services SDK. Ниже описаны новые специальные действия в облаке, которые поставляются с .NET Services SDK.
Поскольку основной задачей .NET Workflow Service является упрощение взаимодействия сообщений, эти действия, главным образом, касаются отправки, получения и обработки сообщений. Отправлять/принимать сообщения можно посредством традиционных HTTP-запросов или через .NET Service Bus. Эти действия можно будет найти на панели инструментов Visual Studio при использовании шаблона проекта последовательного рабочего процесса в облаке.
Платформа Azure™ Services Platform представляет комплексную стратегию, разработанную Microsoft для облегчения разработчикам задач по реализации возможностей обработки данных в облаке. Microsoft® .NET Services – ключевая составляющая этой платформы, созданная специально, чтобы помочь .NET-разработчикам сделать первый шаг. .NET Services предлагает ориентированные на работу в облаке стандартные блоки и инфраструктуру для обеспечения возможности подключения приложений, управления доступом, размещения и управления рабочим процессом. Эти стандартные блоки станут основными средствами организации работы "с облаком" для .NET-разработчиков на годы вперед. Больше информации о .NET Service Bus, .NET Access Control Service и .NET Workflow Service можно найти в документах данной серии, посвященных каждой из этих тем в отдельности.
Microsoft® .NET Service Bus – блок сервисов, который предоставляет сетевую инфраструктуру для соединения приложений через Интернет с использованием разнообразных шаблонов обмена сообщениями способом, обеспечивающим возможность прохождения межсетевых экранов и NAT-устройств без нарушения безопасности, предоставляемой этими устройствами.
Microsoft® .NET Access Control Service – блок сервисов, который обеспечивает управление доступом в облаке на основании утверждений. Он включает механизм преобразования утверждений, который объединяется с поставщиками удостоверений, такими как Active Directory и Windows Live ID (WLID). В будущих версиях будет реализована интеграция с любыми поставщиками удостоверений.
Microsoft® .NET Workflow Services – блок сервисов, который предоставляет инфраструктуру для размещения и управления рабочими процессами WF, уделяя основной внимание взаимодействию через сообщения посредством
Целью лабораторной работы является практическое освоение создания приложений Windows Azure.
Аппаратура и программные инструменты, необходимые для лабораторной работы
Продолжительность лабораторной работы
2 академических часа
public class GuestBookEntry :
Microsoft.WindowsAzure.StorageClient.TableServiceEntity
{
}
public GuestBookEntry()
{
PartitionKey = DateTime.UtcNow.ToString("MMddyyyy");
// Row key allows sorting, so we make sure the rows come back in time order.
RowKey = string.Format("{0:10}_{1}", DateTime.MaxValue.Ticks - DateTime.Now.Ticks, Guid.NewGuid());
}
public string Message { get; set; }
public string GuestName { get; set; }
public string PhotoUrl { get; set; }
public string ThumbnailUrl { get; set; }
using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.StorageClient;
public class GuestBookDataContext : TableServiceContext
{
public GuestBookDataContext(string baseAddress, StorageCredentials credentials)
: base(baseAddress, credentials)
{ }
}
public class GuestBookDataContext : TableServiceContext
{
...
public IQueryable<GuestBookEntry> GuestBookEntry
{
get
{
return this.CreateQuery<GuestBookEntry>("GuestBookEntry");
}
}
}
using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.StorageClient;
public class GuestBookEntryDataSource
{
private static CloudStorageAccount storageAccount;
private GuestBookDataContext context;
}
public class GuestBookEntryDataSource
{
private static CloudStorageAccount storageAccount;
private GuestBookDataContext context;
static GuestBookEntryDataSource()
{
storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
CloudTableClient.CreateTablesFromModel(
typeof(GuestBookDataContext),
storageAccount.TableEndpoint.AbsoluteUri,
storageAccount.Credentials);
}
}
public GuestBookEntryDataSource()
{
this.context = new GuestBookDataContext(storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials);
this.context.RetryPolicy = RetryPolicies.Retry(3, TimeSpan.FromSeconds(1));
}
public IEnumerable<GuestBookEntry> Select()
{
var results = from g in this.context.GuestBookEntry
where g.PartitionKey == DateTime.UtcNow.ToString("MMddyyyy")
select g;
return results;
}
public void UpdateImageThumbnail(string partitionKey, string rowKey, string thumbUrl)
{
var results = from g in this.context.GuestBookEntry
where g.PartitionKey == partitionKey g.RowKey == rowKey
select g;
var entry = results.FirstOrDefault<GuestBookEntry>();
entry.ThumbnailUrl = thumbUrl;
this.context.UpdateObject(entry);
this.context.SaveChanges();
}
using System.IO; using System.Net; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.ServiceRuntime; using Microsoft.WindowsAzure.StorageClient; using GuestBook_Data;
private static bool storageInitialized = false; private static object gate = new Object(); private static CloudBlobClient blobStorage;
protected void SignButton_Click(object sender, EventArgs e)
{
if (FileUpload1.HasFile)
{
InitializeStorage();
// upload the image to blob storage
CloudBlobContainer container = blobStorage.GetContainerReference("guestbookpics");
string uniqueBlobName = string.Format("image_{0}.jpg", Guid.NewGuid().ToString());
CloudBlockBlob blob = container.GetBlockBlobReference(uniqueBlobName);
blob.Properties.ContentType = FileUpload1.PostedFile.ContentType;
blob.UploadFromStream(FileUpload1.FileContent);
System.Diagnostics.Trace.TraceInformation("Uploaded image '{0}'
to blob storage as '{1}'", FileUpload1.FileName, uniqueBlobName);
// create a new entry in table storage
GuestBookEntry entry = new GuestBookEntry() { GuestName = NameTextBox.Text,
Message = MessageTextBox.Text, PhotoUrl = blob.Uri.ToString(), ThumbnailUrl = blob.Uri.ToString() };
GuestBookEntryDataSource ds = new GuestBookEntryDataSource();
ds.AddGuestBookEntry(entry);
System.Diagnostics.Trace.TraceInformation("Added entry {0}-{1} in table storage for guest
'{2}'", entry.PartitionKey, entry.RowKey, entry.GuestName);
}
NameTextBox.Text = "";
MessageTextBox.Text = "";
DataList1.DataBind();
}
protected void Timer1_Tick(object sender, EventArgs e)
{
DataList1.DataBind();
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Timer1.Enabled = true;
}
}
private void InitializeStorage()
{
if (storageInitialized)
{
return;
}
lock (gate)
{
if (storageInitialized)
{
return;
}
try
{
// read account configuration settings
var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
// create blob container for images
blobStorage = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobStorage.GetContainerReference("guestbookpics");
container.CreateIfNotExist();
// configure container for public access
var permissions = container.GetPermissions();
permissions.PublicAccess = BlobContainerPublicAccessType.Container;
container.SetPermissions(permissions);
}
catch (WebException)
{
throw new WebException("Storage services initialization failure. "
+ "Check your storage account configuration settings. If running locally, "
+ "ensure that the Development Storage service is running.");
}
storageInitialized = true;
}
}
using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.ServiceRuntime;
void Application_Start(object sender, EventArgs e)
{
Microsoft.WindowsAzure.CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
{
configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
});
}
public partial class _Default : System.Web.UI.Page
{
private static bool storageInitialized = false;
private static object gate = new Object();
private static CloudBlobClient blobStorage;
private static CloudQueueClient queueStorage;
...
}
public partial class Default : System.Web.UI.Page
{
...
private void InitializeStorage()
{
...
try
{
...
// configure container for public access
var permissions = container.GetPermissions();
permissions.PublicAccess = BlobContainerPublicAccessType.Container;
container.SetPermissions(permissions);
// create queue to communicate with worker role
queueStorage = storageAccount.CreateCloudQueueClient();
CloudQueue queue = queueStorage.GetQueueReference("guestthumbs");
queue.CreateIfNotExist();
}
catch (WebException)
{
...
}

Целью лабораторной работы является практическое освоение процесса развертывания приложений Windows Azure.
Аппаратура и программные инструменты, необходимые для лабораторной работы
Продолжительность лабораторной работы
2 академических часа
[YOUR_ACCOUNT_NAME] на значение Storage Account Name , которое Вы выбрали когда настраивали Storage account в Задании 1.

Целью лабораторной работы является практическое освоение процесса работы с Blob в Windows Azure.
Аппаратура и программные инструменты, необходимые для лабораторной работы
Продолжительность лабораторной работы
2 академических часа

using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.StorageClient; using Microsoft.WindowsAzure.ServiceRuntime;
private void EnsureContainerExists()
{
var container = GetContainer();
container.CreateIfNotExist();
var permissions = container.GetPermissions();
permissions.PublicAccess = BlobContainerPublicAccessType.Container;
container.SetPermissions(permissions);
}
private CloudBlobContainer GetContainer()
{
// Get a handle on account, create a blob storage client and get container proxy
var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
var client = account.CreateCloudBlobClient();
return client.GetContainerReference(RoleEnvironment.GetConfigurationSettingValue("ContainerName"));
}
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (!IsPostBack)
{
this.EnsureContainerExists();
}
this.RefreshGallery();
}
catch (System.Net.WebException we)
{
status.Text = "Network error: " + we.Message;
if (we.Status == System.Net.WebExceptionStatus.ConnectFailure)
{
status.Text += "<br />Please check if the blob storage service is running at " +
ConfigurationManager.AppSettings["storageEndpoint"];
}
}
catch (StorageException se)
{
Console.WriteLine("Storage service error: " + se.Message);
}
}
private void RefreshGallery()
{
images.DataSource =
this.GetContainer().ListBlobs(new BlobRequestOptions()
{
UseFlatBlobListing = true,
BlobListingDetails = BlobListingDetails.All
});
images.DataBind();
}

private void SaveImage(string id, string name, string description,
string tags, string fileName, string contentType, byte[] data)
{
// Create a blob in container and upload image bytes to it
var blob = this.GetContainer().GetBlobReference(name);
blob.Properties.ContentType = contentType;
// Create some metadata for this image
var metadata = new NameValueCollection();
metadata["Id"] = id;
metadata["Filename"] = fileName;
metadata["ImageName"] = String.IsNullOrEmpty(name) ? "unknown" : name;
metadata["Description"] = String.IsNullOrEmpty(description) ? "unknown" : description;
metadata["Tags"] = String.IsNullOrEmpty(tags) ? "unknown" : tags;
// Add and commit metadata to blob
blob.Metadata.Add(metadata);
blob.UploadByteArray(data);
}
protected void upload_Click(object sender, EventArgs e)
{
if (imageFile.HasFile)
{
status.Text = "Inserted [" + imageFile.FileName + "] -
Content Type [" + imageFile.PostedFile.ContentType + "] -
Length [" + imageFile.PostedFile.ContentLength + "]";
this.SaveImage(
Guid.NewGuid().ToString(),
imageName.Text,
imageDescription.Text,
imageTags.Text,
imageFile.FileName,
imageFile.PostedFile.ContentType,
imageFile.FileBytes
);
RefreshGallery();
}
else
status.Text = "No image file";
}
protected void OnBlobDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
var metadataRepeater = e.Item.FindControl("blobMetadata") as Repeater;
var blob = ((ListViewDataItem)(e.Item)).DataItem as CloudBlob;
// If this blob is a snapshot, rename button to "Delete Snapshot"
if (blob != null)
{
if(blob.SnapshotTime.HasValue)
{
var delBtn = e.Item.FindControl("deleteBlob") as LinkButton;
if (delBtn != null) delBtn.Text = "Delete Snapshot";
var snapshotBtn = e.Item.FindControl("SnapshotBlob") as LinkButton;
if (snapshotBtn != null) snapshotBtn.Visible = false;
}
if (metadataRepeater != null)
{
//bind to metadata
metadataRepeater.DataSource = from key in blob.Metadata.AllKeys
select new
{
Name = key,
Value = blob.Metadata[key]
};
metadataRepeater.DataBind();
}
}
}
}
<div class="item">
<ul style="width:40em;float:left;clear:left" >
<asp:Repeater ID="blobMetadata" runat="server">
<ItemTemplate>
<%# Eval("Name") %><span><%# Eval("Value") %></span>
</ItemTemplate>
</asp:Repeater>
<asp:LinkButton ID="deleteBlob"
OnClientClick="return confirm('Delete image?');"
CommandName="Delete"
CommandArgument='<%# Eval("Uri")%>'
runat="server" Text="Delete" oncommand="OnDeleteImage" />
</ul>
<img src="<%# Eval("Uri") %>" alt="<%# Eval("Uri") %>" style="float:left"/>
</div>
protected void OnDeleteImage(object sender, CommandEventArgs e)
{
try
{
if (e.CommandName == "Delete")
{
var blobUri = (string)e.CommandArgument;
var blob = this.GetContainer().GetBlobReference(blobUri);
blob.DeleteIfExists();
RefreshGallery();
}
}
catch (StorageClientException se)
{
status.Text = "Storage client error: " + se.Message;
}
catch (Exception) { }
}
<div class="item">
<ul style="width:40em;float:left;clear:left" >
<asp:Repeater ID="blobMetadata" runat="server">
<ItemTemplate>
<%# Eval("Name") %><span><%# Eval("Value") %></span>
</ItemTemplate>
</asp:Repeater>
<asp:LinkButton ID="deleteBlob"
OnClientClick="return confirm('Delete image?');"
CommandName="Delete"
CommandArgument='<%# Eval("Uri")%>'
runat="server" Text="Delete" oncommand="OnDeleteImage" />
<asp:LinkButton ID="CopyBlob"
OnClientClick="return confirm('Copy image?');"
CommandName="Copy"
CommandArgument='<%# Eval("Uri")%>'
runat="server" Text="Copy" oncommand="OnCopyImage" />
</ul>
<img src="<%# Eval("Uri") %>" alt="<%# Eval("Uri") %>" style="float:left"/>
</div>
protected void OnCopyImage(object sender, CommandEventArgs e)
{
if (e.CommandName == "Copy")
{
// Prepare an Id for the copied blob
var newId = Guid.NewGuid();
// Get source blob
var blobUri = (string)e.CommandArgument;
var srcBlob = this.GetContainer().GetBlobReference(blobUri);
// Create new blob
var newBlob = this.GetContainer().GetBlobReference(newId.ToString());
// Copy content from source blob
newBlob.CopyFromBlob(srcBlob);
// Explicitly get metadata for new blob
newBlob.FetchAttributes(new BlobRequestOptions{BlobListingDetails = BlobListingDetails.Metadata});
// Change metadata on the new blob to reflect this is a copy via UI
newBlob.Metadata["ImageName"] = "Copy of \"" + newBlob.Metadata["ImageName"] + "\"";
newBlob.Metadata["Id"] = newId.ToString();
newBlob.SetMetadata();
// Render all blobs
RefreshGallery();
}
}
<div class="item">
<ul style="width:40em;float:left;clear:left" >
<asp:Repeater ID="blobMetadata" runat="server">
<ItemTemplate>
<%# Eval("Name") %><span><%# Eval("Value") %></span>
</ItemTemplate>
</asp:Repeater>
<asp:LinkButton ID="deleteBlob"
OnClientClick="return confirm('Delete image?');"
CommandName="Delete"
CommandArgument='<%# Eval("Uri")%>'
runat="server" Text="Delete" oncommand="OnDeleteImage" />
<asp:LinkButton ID="CopyBlob"
OnClientClick="return confirm('Copy image?');"
CommandName="Copy"
CommandArgument='<%# Eval("Uri")%>'
runat="server" Text="Copy" oncommand="OnCopyImage" />
<asp:LinkButton ID="SnapshotBlob"
OnClientClick="return confirm('Snapshot image?');"
CommandName="Snapshot"
CommandArgument='<%# Eval("Uri")%>'
runat="server" Text="Snapshot" oncommand="OnSnapshotImage" />
</ul>
<img src="<%# Eval("Uri") %>" alt="<%# Eval("Uri") %>" style="float:left"/>
</div>
protected void OnSnapshotImage(object sender, CommandEventArgs e)
{
if (e.CommandName == "Snapshot")
{
// Get source blob
var blobUri = (string) e.CommandArgument;
var srcBlob = this.GetContainer().GetBlobReference(blobUri);
// Create a snapshot
var snapshot = srcBlob.CreateSnapshot();
status.Text = "A snapshot has been taken for image blob:" + srcBlob.Uri + " at " + snapshot.SnapshotTime;
RefreshGallery();
}
}
Целью лабораторной работы является практическое освоение процесса работы с Tables в Windows Azure.
Аппаратура и программные инструменты, необходимые для лабораторной работы
Продолжительность лабораторной работы
2 академических часа

public class Message :
Microsoft.WindowsAzure.StorageClient.TableServiceEntity
{
}
public Message()
{
PartitionKey = "a";
RowKey = string.Format("{0:10}_{1}", DateTime.MaxValue.Ticks - DateTime.Now.Ticks, Guid.NewGuid());
}
public string Name { get; set; }
public string Body { get; set; }
using Microsoft.WindowsAzure.StorageClient; using Microsoft.WindowsAzure;
namespace RdChat_WebRole
{
public class MessageDataServiceContext : TableServiceContext
{
public MessageDataServiceContext(string baseAddress, StorageCredentials credentials)
: base(baseAddress, credentials)
{
}
}
}
public IQueryable<Message> Messages
{
get
{
return this.CreateQuery<Message>("Messages");
}
}
public void AddMessage(string name, string body)
{
this.AddObject("Messages", new Message { Name = name, Body = body });
this.SaveChanges();
}
protected void Application_Start()
{
...
/// Create data table from MessageDataServiceContext
/// It is recommended the data tables should be only created once. It is typically done as a
/// provisioning step and rarely in application code.
var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
// dynamically create the tables
CloudTableClient.CreateTablesFromModel(typeof(MessageDataServiceContext),
account.TableEndpoint.AbsoluteUri, account.Credentials);
}
using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.ServiceRuntime; using Microsoft.WindowsAzure.StorageClient;
using System.Data.Services.Client; using Microsoft.WindowsAzure;
protected void SubmitButton_Click(object sender, EventArgs e)
{
var statusMessage = String.Empty;
try
{
var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
var context = new MessageDataServiceContext(account.TableEndpoint.ToString(), account.Credentials);
context.AddMessage(this.nameBox.Text, this.messageBox.Text);
this.messageList.DataSource = context.Messages;
this.messageList.DataBind();
}
catch (DataServiceRequestException ex)
{
statusMessage = "Unable to connect to the table storage server. Please check that the service is running.<br>"
+ ex.Message;
}
status.Text = statusMessage;
}

Цель данной лекции – ознакомиться с технологиями Microsoft .NET Services.
.NET Services предоставляет основные стандартные блоки, которые понадобятся при построении приложений в облаке и работающих с облаком для Azure™ Services Platform.
Сервисы, собранные под именем .NET Services, обеспечивают инфраструктуру облака, которая, в конечном счете, упрощает построение работающих в облаке приложений.
Сегодня .NET Services обеспечивают основную функциональность, связанную с возможностями подключения приложений, управления доступом и взаимодействия посредством сообщений на базе рабочего процесса. Со временем они будут предоставлять больший набор функций и среду на базе облака. На данный момент под именем .NET Services объединены следующие основные блоки сервисов:
Данные новые сервисы можно рассматривать как .NET-инфраструктуру сервисов для облака. Все они доступны через открытые протоколы и стандарты, включая REST, SOAP, Atom/AtomPub и WS. Это означает, что разработчики на любой платформе могут интегрироваться с этими сервисами.
Однако, в попытке сделать все максимально привычным для .NET-разработчиков, Microsoft также предоставляет .NET Services SDK, который обеспечивает первоклассные условия для .NET-разработчика и скрывает многие сложные моменты работы с сервисами.
.NET Services SDK позволяет разработчикам использовать имеющийся опыт .NET-разработки, в частности в областях WCF и WF, через применение новых расширений инфраструктуры SDK (например, новых привязок, каналов и действия). SDK также включает поддержку инструментов Visual Studio для интеграции с порталом Azure™ Services Portal. Кроме .NET Services SDK, сегодня партнеры Microsoft предлагают Java и Ruby SDK (ссылки можно найти в разделе " Дополнительные ресурсы ").
Чтобы начать работу с .NET Services, перейдите на портал Azure™ Services Platform по адресу http://azure.com и щелкните ссылку "Try It Now" (Попробуйте сейчас). Вы перейдете на страницу " Register for Azure Services " (Регистрация для сервисов Azure), представленную на рисунке 8.1. На этой странице даются важные ссылки для скачивания различных SDK, доступа к дополнительным ресурсам и перехода на сайт Microsoft Connect, где можно зарегистрироваться для получения кода приглашения.
(рис 8.1) Портал Azure™ Services Platform
Далее потребуется загрузить .NET Services SDK. Обратите внимание, что имеется несколько SDK: один – специально предназначенный для разработки Windows® Azure™; другой – для разработки .NET Services; и остальные – для SQL Data Services и Live Framework. Для воспроизведения примеров, предлагаемых в данной серии документов, понадобится скачать и установить .NET Services SDK.
Скачав .NET Services SDK, просто запустите программу установки, как показано на рисунке 8.2. Тем самым вам будут доступны новые .NET-сборки, которые вместе с некоторыми надстройками Visual Studio помогут начать использование различных функций .NET Services. Приступая к работе с .NET Services, обязательно ознакомьтесь с остальными ресурсами, доступными с этой страницы (демонстрации, видео, практические лабораторные и т.д.), цель которых – сделать процесс обучения более насыщенным и разнообразным. Скачать SDK можно, не создавая учетной записи, но, чтобы использовать сервисы, необходимо зарегистрироваться.
(рис 8.2) Запуск установки NET Services SDK
Чтобы зарегистрироваться на получения учетной записи Azure Services, щелкните показанную выше ссылку " Register for Services " (Регистрация для сервисов). Вам будет предложено зарегистрироваться, используя Windows Live ID (WLID). После этого вы перейдете на сайт Microsoft Connect, где потребуется заполнить регистрационную форму Azure Services
(рис 8.3) Регистрация для Azure Services Platform на сайте Microsoft Connect
Теперь можно вернуться на страницу входа .NET Services Эту страницу можно увидеть на рисунке 8.4.
(рис 8.4) Страница входа .NET Services
Теперь, щелкнув " Sign Up " (Войти), вы получаете возможность создавать решение .NET Services. Примечание: в
Для создания решения необходимо просто ввести уникальное имя решения, принять условия использования и нажать " Create Solution " (Создать решение). После этого новое решение будет подготовлено и ассоциировано с вашим WLID. Теперь, в любой момент, зарегистрировавшись на портале Azure™ Services Platform, вы имеете возможность управлять решениями, ассоциированными с вашим WLID.
Имя решения должно быть не менее 6 символов длиной и глобально уникальным среди всех пользователей .NET-сервисов. Возможно, придется проявить смекалку, чтобы придумать такое имя для решения, которое еще не используется никем другим.
После того, как новое решение создано, на экран выводится страница (рисунок 8.5), предлагающая пароль решения, который желательно сохранить для использования в будущем. Имя решения и пароль выступают в роли учетных данных для доступа к различным сервисам .NET Services.
(рис 8.5) Завершение процесса подготовки решения
После успешного создания решения можно приступать к работе с ним на портале Azure™ Services Platform. Зарегистрировавшись под собственным WLID, на странице портала справа вы увидите меню " My Solutions " (Мои решения) (рисунок 8.6). Для работы с конкретным решением необходимо просто выбрать его в меню " My Solutions ", после чего вам будет представлена страница, показанная на рисунке 8.7.
По сути, решение – это контейнер верхнего уровня для организации различных ресурсов .NET Services.Например, в нем размещаются конечные точки .NET Service Bus, типы и экземпляры рабочих процессов .NET Workflow Service, а также ваши удостоверения .NET Access Control Service и правила преобразования утверждений. Но одним из самых важных аспектов, которым вы захотите управлять после создания собственного решения, являются учетные данные решения.
Именно поэтому имя решения должно быть уникальным среди всех пользователей.
(рис 8.6) Управление своими решениями посредством меню "My Solutions"
(рис 8.7) Управление отдельным решением
Пароль решения, предоставленный в процессе подготовки, можно изменить на странице " Credential Management " (Управление учетными данными) (просто щелкните ссылку " Solution Credentials " (Учетные данные решения), которую можно видеть на рис. 8.8). С этой страницы можно также конфигурировать информационные карточки
(рис 8.8) Управление учетными данными своего решения
Для
Самым распространенным требованием в распределенных приложениях с высоким уровнем масштабируемости является возможность подключения приложений. Обычно интеграция приложений – одна из самых дорогостоящих и хлопотных областей ИТ. Сегодня для этих задач многие организации используют решение Enterprise Service Bus. Enterprise Service Bus (сервисная шина предприятия, ESB) — подход к построению распределённых корпоративных информационных систем. Обычно включает в себя промежуточное ПО, которое обеспечивает взаимосвязь между различными приложениями по различным протоколам взаимодействия.
Архитектура
Одним из стандартов взаимодействия являются веб-сервисы. В популярных реализациях
NET Service Bus является основной частью предложения .NET Services. Ее основная задача – сделать шаблон
Internet Service Bus позволила бы интегрировать ваш локальный
Чтобы это стало реальностью, реализация должна обеспечивать интегрированные решения, основанные на открытых Интернет-стандартах, и насыщенную среду обмена сообщениями с возможностью двусторонней связи в Интернет.
(рис 8.9) Сервисная шина Интернет
Реализация двусторонней связи в Интернете не такая уж тривиальная задача из-за некоторых реалий организации современных сетей. Преимущественно, барьеры в сети создают межсетевые экраны и устройства, работающие по протоколу NAT, которые усложняют обмен информацией с узлами, располагающимися за ними. Представьте ситуацию: торговый агент использует ваше приложение по беспроводной сети в случайной гостинице в некоторой точке земного шара. Как при таком сценарии определить его местоположение и инициировать связь?
Часто компании решают эти проблемы связи, открывая входящие порты межсетевых экранов (что доставляет немало хлопот системным администраторам) или используя различных обходные приемы, такие как динамическая DNS, сопоставление портов NAT или технологию
Network address translation – Преобразование сетевых адресов.
Domain Name System – Служба доменных имен.
Universal Plug and Play – Универсальная автоматическая настройка сетевых устройств.
Решение идентификации, реализацией которой Microsoft занимается последние несколько лет, основано на концепции утверждений. Модель идентификации на базе утверждений позволяет выносить общие функции аутентификации и авторизации из приложений и осуществлять их централизованно во внешних сервисах, написанных и обслуживаемых экспертами безопасности и идентификации, что выгодно всем, кто участвует в этом процессе.
Microsoft® .NET Access Control Service – это сервис в облаке, выполняющий именно эту функцию. Вместо того чтобы создавать собственную базу данных пользовательских учетных записей и ролей, можно предоставить возможность .NET Access Control Service управлять аутентификацией и авторизацией ваших пользователей. .NET Access Control Service использует существующие хранилища учетных записей пользователей, такие как Windows Live ID и Active Directory, а также любые другие хранилища, поддерживающие стандартные протоколы интегрирования. Таким образом, использование единой регистрации для доступа ко всем приложениям становится вполне естественным. Также это обеспечивает централизацию логики аутентификации и управления доступом, что упрощает ваши приложения.
В поддерживающих утверждения приложениях пользователь представляет свое удостоверение как набор утверждений. Одним утверждением может быть имя пользователя; другим – его адрес электронной почты. Эти утверждения предоставляются организацией, выдающей удостоверения, которая знает, как аутентифицировать пользователя и где найти его атрибуты. Клиентское приложение, в роли которого может выступать браузер или насыщенный клиент, напрямую получает утверждения от этой организации и передает их в ваше приложение (рисунок 8.10).
(рис 8.10) Использование идентификации на базе утверждений для веб-сервисов
В итоге, приложение получает все сведения, необходимые для идентификации пользователя, в виде набора утверждений. Эти утверждения подписываются, что обеспечивает криптографическое подтверждение их происхождения.
Модель идентификации на базе утверждений упрощает реализацию единой регистрации, при этом приложение больше не отвечает ни за один из перечисленных ниже аспектов безопасности:
Используя такую модель, приложение может принимать решения об идентификации на основании предоставленных пользователем утверждений. И диапазон таких решений велик: от простой персонализации приложения по имени пользователя до авторизации пользователя для доступа к особо важным функциям и ресурсам приложения.
.NET Access Control Service реализовывает идентификацию на базе утверждений в рамках платформы Azure™ Services Platform. Система администрирования является важной частью .NET Access Control Service.
(рис 8.11) Портал ACS
.NET Access Control Service предоставляет портал администрирования (рисунок 8.11) в рамках портала Azure™ Services Portal. Здесь вы выполняете настройку правил, которые определяют схему выпуска утверждений для различных пользователей.
Портал Access Control Service – замечательное средство для исследования, изучения и начала работы с
Сервис .NET Access Control Service также включает конечные точки SOAP и REST для программного администрирования, а также ряд .NET-классов,
которые упрощают вызов этих конечных точек. Итак, если вам не нравится портал, предоставляемый
Самой большой проблемой в построении крупномасштабных распределенных приложений является принятие решения о моделировании сложных схем взаимодействия через обмен сообщениями. Microsoft .NET Workflow Service позволяет разрабатывать логику взаимодействия сообщений с помощью WF и обеспечивает размещенную масштабируемую среду для выполнения и управления экземплярами рабочего процесса WF в облаке, освобождая разработчика от необходимости создания собственного хоста для WF.
.NET Workflow Service является частью Azure™ Services Platform и интегрируется с сервисами .NET Service Bus и .NET Access Control Service для безопасного координирования взаимодействия посредством сообщений. .NET Workflow Service также обеспечивает инструменты управления для создания и управления типами и экземплярами рабочих потоков и API веб-сервисов для ситуаций, когда требуется создать собственные инструменты.
Поскольку управляющая среда построена на платформе Windows® Azure™, она может масштабироваться по требованию и в значительной степени, при этом организации или разработчику не приходится беспокоиться о планировании большего количества оборудования или программного обеспечения. Благодаря использованию среды выполнения WF экземпляры рабочего потока могут выполняться в
На период перехода к обработке данных в облаке .NET Workflow Services предоставляет упрощенный подход для управления сложными взаимодействиями .NET Service Bus в создаваемых вами составных решениях "в облаке".
Построение хоста для рабочих процессов WF означает принятие решений о том, какие возможности будет поддерживать среда и как лучше сделать ее безопасной, масштабируемой и стабильной. Сегодня .NET Workflow Service построен на .NET Framework 3.5 и действиях и компонентах WF, входящих в данную версию инфраструктуры. Однако для обеспечения наилучших условий Microsoft были добавлены несколько специальных действий и сервисов, которые наложили некоторые ограничения на рабочие процессы, выполняющиеся в облаке.
В облаке не используется сервис хранения SqlWorkflowPersistenceProvider, получивший наибольшую популярность среди разработчиков, применяющих WF. Чтобы использовать операционную среду Azure и обеспечить наилучшие возможности масштабирования и стабильности, в инфраструктуре облака имеется специальный провайдер услуг хранения, который реализует сохранение состояния выполняющихся рабочих процессов посредством возможностей хранения Microsoft SQL Services. Кроме всего прочего, для Интернет-сервиса необходима Интернет-технология хранения и извлечения данных. Но поскольку механизм WF един – как в облаке, так и в ваших локальных решениях, – применение специального провайдера услуг хранения прозрачно для разработчиков рабочих процессов. Все делается так же, как в любой другое среде WF.
При построении рабочих процессов для облака разработчики используют привычные инструменты Visual Studio, включая тот же дизайнер рабочего процесса для создания XAML-файлов рабочих процессов и файлов правил. Затем эти XML-файлы загружаются на сервер в облаке, где они могут использоваться для создания экземпляров рабочего процесса. .NET Services SDK включает шаблон проекта для создания SequentialCloudWorkflow (Последовательный рабочий процесс в облаке), который является специальной версией стандартного шаблона SequentialWorkflow (Последовательный рабочий процесс). Одним из ограничений текущей инфраструктуры является то, что при определении рабочих процессов, которые будут выполняться в облаке, можно использовать только подмножество действий базовой библиотеки действий, а также комплект специальных действий, предоставляемый как часть .NET Services SDK.
Набор действий требует, чтобы рабочие процессы были полностью декларативными и ограничивающими. Это предотвращает введение пользовательского кода, т.е. позволяет гарантировать стабильность среды. При построении управляющей среды для рабочих процессов, написанных любым количеством разработчиков, разбросанных по всему миру, такой уровень контроля является обязательным. Поскольку сегодня для выполнения WF необходимо полное доверие, мы не можем обеспечить ограниченный набор функциональности, просто выделив пользовательский код в безопасную изолированную программную среду на серверах. Следует отметить, что со временем доступный сегодня ограниченный набор действий будет расширен для увеличения возможностей рабочего процесса в облаке. По мере выхода новых версий .NET Framework и .NET Workflow Service также будет поддерживать их. Кроме того, если понадобятся специальные этапы, возможности локальных рабочих процессов могут комбинироваться с рабочими процессами в облаке с помощью .NET Service Bus.
.NET Services SDK содержит новый шаблон проекта для построения рабочих процессов в облаке, набором новых действий в облаке и клиентским API для удаленного развертывания и управления рабочими процессами, размещаемыми в облаке.
При написании рабочих процессов в облаке необходимо быть аккуратным с используемыми действиями (дизайнер предложит только допустимые действия). Разрешенными являются некоторые основные действия потока управления WF, включая IfElse (Если…то), While (Пока), Sequence (Последовательность), Suspend (Приостановить), Terminate (Завершить) и FaultHandler (Обработчик сбоев). Кроме базовых действий потока управления, в рабочих процесса в облаке могут также использоваться CancellationHandlerActivity и FaultHandlersActivity для моделирования обработки исключений и логики отмены. Обратите внимание, что эти действия обычно не добавляются в модель напрямую; для этого используется дизайнер составных действий, который вводит их автоматически, когда представление переходит к этому действию.
Ни одно другое действие WF или пользовательские действия не могут использоваться. Разрешены к применению только новые специальные действия в облаке, включенные в .NET Services SDK. Ниже описаны новые специальные действия в облаке, которые поставляются с .NET Services SDK.
Поскольку основной задачей .NET Workflow Service является упрощение взаимодействия сообщений, эти действия, главным образом, касаются отправки, получения и обработки сообщений. Отправлять/принимать сообщения можно посредством традиционных HTTP-запросов или через .NET Service Bus. Эти действия можно будет найти на панели инструментов Visual Studio при использовании шаблона проекта последовательного рабочего процесса в облаке.
Платформа Azure™ Services Platform представляет комплексную стратегию, разработанную Microsoft для облегчения разработчикам задач по реализации возможностей обработки данных в облаке. Microsoft® .NET Services – ключевая составляющая этой платформы, созданная специально, чтобы помочь .NET-разработчикам сделать первый шаг. .NET Services предлагает ориентированные на работу в облаке стандартные блоки и инфраструктуру для обеспечения возможности подключения приложений, управления доступом, размещения и управления рабочим процессом. Эти стандартные блоки станут основными средствами организации работы "с облаком" для .NET-разработчиков на годы вперед. Больше информации о .NET Service Bus, .NET Access Control Service и .NET Workflow Service можно найти в документах данной серии, посвященных каждой из этих тем в отдельности.
Microsoft® .NET Service Bus – блок сервисов, который предоставляет сетевую инфраструктуру для соединения приложений через Интернет с использованием разнообразных шаблонов обмена сообщениями способом, обеспечивающим возможность прохождения межсетевых экранов и NAT-устройств без нарушения безопасности, предоставляемой этими устройствами.
Microsoft® .NET Access Control Service – блок сервисов, который обеспечивает управление доступом в облаке на основании утверждений. Он включает механизм преобразования утверждений, который объединяется с поставщиками удостоверений, такими как Active Directory и Windows Live ID (WLID). В будущих версиях будет реализована интеграция с любыми поставщиками удостоверений.
Microsoft® .NET Workflow Services – блок сервисов, который предоставляет инфраструктуру для размещения и управления рабочими процессами WF, уделяя основной внимание взаимодействию через сообщения посредством
Целью лабораторной работы является практическое освоение создания приложений Windows Azure.
Аппаратура и программные инструменты, необходимые для лабораторной работы
Продолжительность лабораторной работы
2 академических часа
public class GuestBookEntry :
Microsoft.WindowsAzure.StorageClient.TableServiceEntity
{
}
public GuestBookEntry()
{
PartitionKey = DateTime.UtcNow.ToString("MMddyyyy");
// Row key allows sorting, so we make sure the rows come back in time order.
RowKey = string.Format("{0:10}_{1}", DateTime.MaxValue.Ticks - DateTime.Now.Ticks, Guid.NewGuid());
}
public string Message { get; set; }
public string GuestName { get; set; }
public string PhotoUrl { get; set; }
public string ThumbnailUrl { get; set; }
using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.StorageClient;
public class GuestBookDataContext : TableServiceContext
{
public GuestBookDataContext(string baseAddress, StorageCredentials credentials)
: base(baseAddress, credentials)
{ }
}
public class GuestBookDataContext : TableServiceContext
{
...
public IQueryable<GuestBookEntry> GuestBookEntry
{
get
{
return this.CreateQuery<GuestBookEntry>("GuestBookEntry");
}
}
}
using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.StorageClient;
public class GuestBookEntryDataSource
{
private static CloudStorageAccount storageAccount;
private GuestBookDataContext context;
}
public class GuestBookEntryDataSource
{
private static CloudStorageAccount storageAccount;
private GuestBookDataContext context;
static GuestBookEntryDataSource()
{
storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
CloudTableClient.CreateTablesFromModel(
typeof(GuestBookDataContext),
storageAccount.TableEndpoint.AbsoluteUri,
storageAccount.Credentials);
}
}
public GuestBookEntryDataSource()
{
this.context = new GuestBookDataContext(storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials);
this.context.RetryPolicy = RetryPolicies.Retry(3, TimeSpan.FromSeconds(1));
}
public IEnumerable<GuestBookEntry> Select()
{
var results = from g in this.context.GuestBookEntry
where g.PartitionKey == DateTime.UtcNow.ToString("MMddyyyy")
select g;
return results;
}
public void UpdateImageThumbnail(string partitionKey, string rowKey, string thumbUrl)
{
var results = from g in this.context.GuestBookEntry
where g.PartitionKey == partitionKey g.RowKey == rowKey
select g;
var entry = results.FirstOrDefault<GuestBookEntry>();
entry.ThumbnailUrl = thumbUrl;
this.context.UpdateObject(entry);
this.context.SaveChanges();
}
using System.IO; using System.Net; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.ServiceRuntime; using Microsoft.WindowsAzure.StorageClient; using GuestBook_Data;
private static bool storageInitialized = false; private static object gate = new Object(); private static CloudBlobClient blobStorage;
protected void SignButton_Click(object sender, EventArgs e)
{
if (FileUpload1.HasFile)
{
InitializeStorage();
// upload the image to blob storage
CloudBlobContainer container = blobStorage.GetContainerReference("guestbookpics");
string uniqueBlobName = string.Format("image_{0}.jpg", Guid.NewGuid().ToString());
CloudBlockBlob blob = container.GetBlockBlobReference(uniqueBlobName);
blob.Properties.ContentType = FileUpload1.PostedFile.ContentType;
blob.UploadFromStream(FileUpload1.FileContent);
System.Diagnostics.Trace.TraceInformation("Uploaded image '{0}'
to blob storage as '{1}'", FileUpload1.FileName, uniqueBlobName);
// create a new entry in table storage
GuestBookEntry entry = new GuestBookEntry() { GuestName = NameTextBox.Text,
Message = MessageTextBox.Text, PhotoUrl = blob.Uri.ToString(), ThumbnailUrl = blob.Uri.ToString() };
GuestBookEntryDataSource ds = new GuestBookEntryDataSource();
ds.AddGuestBookEntry(entry);
System.Diagnostics.Trace.TraceInformation("Added entry {0}-{1} in table storage for guest
'{2}'", entry.PartitionKey, entry.RowKey, entry.GuestName);
}
NameTextBox.Text = "";
MessageTextBox.Text = "";
DataList1.DataBind();
}
protected void Timer1_Tick(object sender, EventArgs e)
{
DataList1.DataBind();
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Timer1.Enabled = true;
}
}
private void InitializeStorage()
{
if (storageInitialized)
{
return;
}
lock (gate)
{
if (storageInitialized)
{
return;
}
try
{
// read account configuration settings
var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
// create blob container for images
blobStorage = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobStorage.GetContainerReference("guestbookpics");
container.CreateIfNotExist();
// configure container for public access
var permissions = container.GetPermissions();
permissions.PublicAccess = BlobContainerPublicAccessType.Container;
container.SetPermissions(permissions);
}
catch (WebException)
{
throw new WebException("Storage services initialization failure. "
+ "Check your storage account configuration settings. If running locally, "
+ "ensure that the Development Storage service is running.");
}
storageInitialized = true;
}
}
using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.ServiceRuntime;
void Application_Start(object sender, EventArgs e)
{
Microsoft.WindowsAzure.CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
{
configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
});
}
public partial class _Default : System.Web.UI.Page
{
private static bool storageInitialized = false;
private static object gate = new Object();
private static CloudBlobClient blobStorage;
private static CloudQueueClient queueStorage;
...
}
public partial class Default : System.Web.UI.Page
{
...
private void InitializeStorage()
{
...
try
{
...
// configure container for public access
var permissions = container.GetPermissions();
permissions.PublicAccess = BlobContainerPublicAccessType.Container;
container.SetPermissions(permissions);
// create queue to communicate with worker role
queueStorage = storageAccount.CreateCloudQueueClient();
CloudQueue queue = queueStorage.GetQueueReference("guestthumbs");
queue.CreateIfNotExist();
}
catch (WebException)
{
...
}

Целью лабораторной работы является практическое освоение процесса развертывания приложений Windows Azure.
Аппаратура и программные инструменты, необходимые для лабораторной работы
Продолжительность лабораторной работы
2 академических часа
[YOUR_ACCOUNT_NAME] на значение Storage Account Name , которое Вы выбрали когда настраивали Storage account в Задании 1.

Целью лабораторной работы является практическое освоение процесса работы с Blob в Windows Azure.
Аппаратура и программные инструменты, необходимые для лабораторной работы
Продолжительность лабораторной работы
2 академических часа

using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.StorageClient; using Microsoft.WindowsAzure.ServiceRuntime;
private void EnsureContainerExists()
{
var container = GetContainer();
container.CreateIfNotExist();
var permissions = container.GetPermissions();
permissions.PublicAccess = BlobContainerPublicAccessType.Container;
container.SetPermissions(permissions);
}
private CloudBlobContainer GetContainer()
{
// Get a handle on account, create a blob storage client and get container proxy
var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
var client = account.CreateCloudBlobClient();
return client.GetContainerReference(RoleEnvironment.GetConfigurationSettingValue("ContainerName"));
}
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (!IsPostBack)
{
this.EnsureContainerExists();
}
this.RefreshGallery();
}
catch (System.Net.WebException we)
{
status.Text = "Network error: " + we.Message;
if (we.Status == System.Net.WebExceptionStatus.ConnectFailure)
{
status.Text += "<br />Please check if the blob storage service is running at " +
ConfigurationManager.AppSettings["storageEndpoint"];
}
}
catch (StorageException se)
{
Console.WriteLine("Storage service error: " + se.Message);
}
}
private void RefreshGallery()
{
images.DataSource =
this.GetContainer().ListBlobs(new BlobRequestOptions()
{
UseFlatBlobListing = true,
BlobListingDetails = BlobListingDetails.All
});
images.DataBind();
}

private void SaveImage(string id, string name, string description,
string tags, string fileName, string contentType, byte[] data)
{
// Create a blob in container and upload image bytes to it
var blob = this.GetContainer().GetBlobReference(name);
blob.Properties.ContentType = contentType;
// Create some metadata for this image
var metadata = new NameValueCollection();
metadata["Id"] = id;
metadata["Filename"] = fileName;
metadata["ImageName"] = String.IsNullOrEmpty(name) ? "unknown" : name;
metadata["Description"] = String.IsNullOrEmpty(description) ? "unknown" : description;
metadata["Tags"] = String.IsNullOrEmpty(tags) ? "unknown" : tags;
// Add and commit metadata to blob
blob.Metadata.Add(metadata);
blob.UploadByteArray(data);
}
protected void upload_Click(object sender, EventArgs e)
{
if (imageFile.HasFile)
{
status.Text = "Inserted [" + imageFile.FileName + "] -
Content Type [" + imageFile.PostedFile.ContentType + "] -
Length [" + imageFile.PostedFile.ContentLength + "]";
this.SaveImage(
Guid.NewGuid().ToString(),
imageName.Text,
imageDescription.Text,
imageTags.Text,
imageFile.FileName,
imageFile.PostedFile.ContentType,
imageFile.FileBytes
);
RefreshGallery();
}
else
status.Text = "No image file";
}
protected void OnBlobDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
var metadataRepeater = e.Item.FindControl("blobMetadata") as Repeater;
var blob = ((ListViewDataItem)(e.Item)).DataItem as CloudBlob;
// If this blob is a snapshot, rename button to "Delete Snapshot"
if (blob != null)
{
if(blob.SnapshotTime.HasValue)
{
var delBtn = e.Item.FindControl("deleteBlob") as LinkButton;
if (delBtn != null) delBtn.Text = "Delete Snapshot";
var snapshotBtn = e.Item.FindControl("SnapshotBlob") as LinkButton;
if (snapshotBtn != null) snapshotBtn.Visible = false;
}
if (metadataRepeater != null)
{
//bind to metadata
metadataRepeater.DataSource = from key in blob.Metadata.AllKeys
select new
{
Name = key,
Value = blob.Metadata[key]
};
metadataRepeater.DataBind();
}
}
}
}
<div class="item">
<ul style="width:40em;float:left;clear:left" >
<asp:Repeater ID="blobMetadata" runat="server">
<ItemTemplate>
<%# Eval("Name") %><span><%# Eval("Value") %></span>
</ItemTemplate>
</asp:Repeater>
<asp:LinkButton ID="deleteBlob"
OnClientClick="return confirm('Delete image?');"
CommandName="Delete"
CommandArgument='<%# Eval("Uri")%>'
runat="server" Text="Delete" oncommand="OnDeleteImage" />
</ul>
<img src="<%# Eval("Uri") %>" alt="<%# Eval("Uri") %>" style="float:left"/>
</div>
protected void OnDeleteImage(object sender, CommandEventArgs e)
{
try
{
if (e.CommandName == "Delete")
{
var blobUri = (string)e.CommandArgument;
var blob = this.GetContainer().GetBlobReference(blobUri);
blob.DeleteIfExists();
RefreshGallery();
}
}
catch (StorageClientException se)
{
status.Text = "Storage client error: " + se.Message;
}
catch (Exception) { }
}
<div class="item">
<ul style="width:40em;float:left;clear:left" >
<asp:Repeater ID="blobMetadata" runat="server">
<ItemTemplate>
<%# Eval("Name") %><span><%# Eval("Value") %></span>
</ItemTemplate>
</asp:Repeater>
<asp:LinkButton ID="deleteBlob"
OnClientClick="return confirm('Delete image?');"
CommandName="Delete"
CommandArgument='<%# Eval("Uri")%>'
runat="server" Text="Delete" oncommand="OnDeleteImage" />
<asp:LinkButton ID="CopyBlob"
OnClientClick="return confirm('Copy image?');"
CommandName="Copy"
CommandArgument='<%# Eval("Uri")%>'
runat="server" Text="Copy" oncommand="OnCopyImage" />
</ul>
<img src="<%# Eval("Uri") %>" alt="<%# Eval("Uri") %>" style="float:left"/>
</div>
protected void OnCopyImage(object sender, CommandEventArgs e)
{
if (e.CommandName == "Copy")
{
// Prepare an Id for the copied blob
var newId = Guid.NewGuid();
// Get source blob
var blobUri = (string)e.CommandArgument;
var srcBlob = this.GetContainer().GetBlobReference(blobUri);
// Create new blob
var newBlob = this.GetContainer().GetBlobReference(newId.ToString());
// Copy content from source blob
newBlob.CopyFromBlob(srcBlob);
// Explicitly get metadata for new blob
newBlob.FetchAttributes(new BlobRequestOptions{BlobListingDetails = BlobListingDetails.Metadata});
// Change metadata on the new blob to reflect this is a copy via UI
newBlob.Metadata["ImageName"] = "Copy of \"" + newBlob.Metadata["ImageName"] + "\"";
newBlob.Metadata["Id"] = newId.ToString();
newBlob.SetMetadata();
// Render all blobs
RefreshGallery();
}
}
<div class="item">
<ul style="width:40em;float:left;clear:left" >
<asp:Repeater ID="blobMetadata" runat="server">
<ItemTemplate>
<%# Eval("Name") %><span><%# Eval("Value") %></span>
</ItemTemplate>
</asp:Repeater>
<asp:LinkButton ID="deleteBlob"
OnClientClick="return confirm('Delete image?');"
CommandName="Delete"
CommandArgument='<%# Eval("Uri")%>'
runat="server" Text="Delete" oncommand="OnDeleteImage" />
<asp:LinkButton ID="CopyBlob"
OnClientClick="return confirm('Copy image?');"
CommandName="Copy"
CommandArgument='<%# Eval("Uri")%>'
runat="server" Text="Copy" oncommand="OnCopyImage" />
<asp:LinkButton ID="SnapshotBlob"
OnClientClick="return confirm('Snapshot image?');"
CommandName="Snapshot"
CommandArgument='<%# Eval("Uri")%>'
runat="server" Text="Snapshot" oncommand="OnSnapshotImage" />
</ul>
<img src="<%# Eval("Uri") %>" alt="<%# Eval("Uri") %>" style="float:left"/>
</div>
protected void OnSnapshotImage(object sender, CommandEventArgs e)
{
if (e.CommandName == "Snapshot")
{
// Get source blob
var blobUri = (string) e.CommandArgument;
var srcBlob = this.GetContainer().GetBlobReference(blobUri);
// Create a snapshot
var snapshot = srcBlob.CreateSnapshot();
status.Text = "A snapshot has been taken for image blob:" + srcBlob.Uri + " at " + snapshot.SnapshotTime;
RefreshGallery();
}
}
Целью лабораторной работы является практическое освоение процесса работы с Tables в Windows Azure.
Аппаратура и программные инструменты, необходимые для лабораторной работы
Продолжительность лабораторной работы
2 академических часа

public class Message :
Microsoft.WindowsAzure.StorageClient.TableServiceEntity
{
}
public Message()
{
PartitionKey = "a";
RowKey = string.Format("{0:10}_{1}", DateTime.MaxValue.Ticks - DateTime.Now.Ticks, Guid.NewGuid());
}
public string Name { get; set; }
public string Body { get; set; }
using Microsoft.WindowsAzure.StorageClient; using Microsoft.WindowsAzure;
namespace RdChat_WebRole
{
public class MessageDataServiceContext : TableServiceContext
{
public MessageDataServiceContext(string baseAddress, StorageCredentials credentials)
: base(baseAddress, credentials)
{
}
}
}
public IQueryable<Message> Messages
{
get
{
return this.CreateQuery<Message>("Messages");
}
}
public void AddMessage(string name, string body)
{
this.AddObject("Messages", new Message { Name = name, Body = body });
this.SaveChanges();
}
protected void Application_Start()
{
...
/// Create data table from MessageDataServiceContext
/// It is recommended the data tables should be only created once. It is typically done as a
/// provisioning step and rarely in application code.
var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
// dynamically create the tables
CloudTableClient.CreateTablesFromModel(typeof(MessageDataServiceContext),
account.TableEndpoint.AbsoluteUri, account.Credentials);
}
using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.ServiceRuntime; using Microsoft.WindowsAzure.StorageClient;
using System.Data.Services.Client; using Microsoft.WindowsAzure;
protected void SubmitButton_Click(object sender, EventArgs e)
{
var statusMessage = String.Empty;
try
{
var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
var context = new MessageDataServiceContext(account.TableEndpoint.ToString(), account.Credentials);
context.AddMessage(this.nameBox.Text, this.messageBox.Text);
this.messageList.DataSource = context.Messages;
this.messageList.DataBind();
}
catch (DataServiceRequestException ex)
{
statusMessage = "Unable to connect to the table storage server. Please check that the service is running.<br>"
+ ex.Message;
}
status.Text = statusMessage;
}

Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.