Введение в облачные решения Microsoft

Работа с Windows Azure Blob

Разбить на страницы
Показывать лекцию целиком

В качестве примера рассмотрим работу простого веб - приложения для загрузки изображений в хранилище Windows Azure Blob:

  • подготовка приложения;
  • загрузка и отображение изображений;
  • удаление сущностей;
  • копирование сущностей.
  • Создайте проект облачной службы и добавьте веб - роль в решение.

    В свойствах веб - роли определим строку подключения к эмулятору хранилища Azure.

    (рис 20.1)

    Также нам понадобится строковый параметр ContainerName, определяющий имя Blob - контейнера для изображений.

    (рис 20.2)

    Задание 1. Подготовка приложени

    Создадим веб - форму AzureBlobSamle.aspx и добавим ссылки в C# класс данной страницы

    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.ServiceRuntime;
    using Microsoft.WindowsAzure.StorageClient;
    using System.Configuration;

    Далее, поскольку Blob - контейнер должен быть доступным для анонимных пользователей необходимо создать метод, подтверждающий наличие контейнера:

    private void EnsureContainerExists()
            {
                var container = GetContainer();
                container.CreateIfNotExist();
                var permissions = container.GetPermissions();
                permissions.PublicAccess = BlobContainerPublicAccessType.Container;
                container.SetPermissions(permissions);
            }

    Как видно, в данном методе присутствует ссылка на несуществующий пока GetConteiner() , который должен возвращать Blob-контейнер для осуществления операций с Blob-объектами.

    private CloudBlobContainer GetContainer()
            {
                CloudStorageAccount.SetConfigurationSettingPublisher(
                    (configName, configSettingPublisher) =>
                    {
                        var connectionString =
                            RoleEnvironment.GetConfigurationSettingValue(configName);
                        configSettingPublisher(connectionString);
                    }
                );
    
                var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
                var client = account.CreateCloudBlobClient();
                return client.GetContainerReference(RoleEnvironment.GetConfigurationSettingValue("ContainerName"));
            }

    Интерфейс

    Теперь необходимо заняться самой формой. На форме буду присутствовать текстовые поля, задающие параметры изображения и диалог загрузки файла.

    (рис 20.3)

    asp - код веб формы:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AzureBlobSample.aspx.cs"
      Inherits="WebRole1.AzureBlobSample" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
        
            <asp:Label ID="Label1" runat="server" Font-Bold="True" Font-Size="X-Large" 
                Text="My Image Gallery - Azure Blob Example"></asp:Label>
            <br />
            <br />
            <table style="width:100%;">
                <tr>
                    <td>
                        <asp:Label ID="lb_name" runat="server" Text="Название"></asp:Label>
                    </td>
                    <td>
                        <asp:TextBox ID="tb_label" runat="server"></asp:TextBox>
                    </td>
                </tr>
                <tr>
                    <td>
                        <asp:Label ID="lb_desc" runat="server" Text="Описание"></asp:Label>
                    </td>
                    <td>
                        <asp:TextBox ID="tb_desc" runat="server"></asp:TextBox>
                    </td>
                </tr>
                <tr>
                    <td>
                         </td>
                    <td>
                         </td>
                </tr>
                <tr>
                    <td>
                        <asp:Label ID="lb_file" runat="server" Text="Файл"></asp:Label>
                    </td>
                    <td>
                        <asp:FileUpload ID="fu_upload" runat="server" />
                    </td>
                </tr>
                <tr>
                    <td>
                         </td>
                    <td>
                        <asp:Button ID="btn_upload" runat="server" onclick="btn_upload_Click" 
                            Text="Загрузить" />
                    </td>
                </tr>
                <tr>
                    <td>
                         </td>
                    <td>
                         </td>
                </tr>
                <tr>
                    <td>
                        <asp:Label ID="lb_status" runat="server"></asp:Label>
                    </td>
                    <td>
                        <asp:ListView ID="lv_images" runat="server">
                <LayoutTemplate>
                    <asp:PlaceHolder ID="itemPlaceholder" runat="server" />
                </LayoutTemplate>
                <EmptyDataTemplate>
                    <h2>No Data Available</h2>
                </EmptyDataTemplate>
                <ItemTemplate>            
                    <div class="item">
                        <ul style="width:40em;float:left;clear:left" >
                            <asp:Repeater ID="blobMetadata" runat="server">
                            <ItemTemplate>
                                <li><%# Eval("Name") %><span><%# Eval("Value") %></span></li>
                            </ItemTemplate>
                            </asp:Repeater>
                            <li>
    
                            </li>
                        </ul>
                        <img src="<%# Eval("Uri") %>" alt="<%# Eval("Uri") %>" style="float:left"/>
                    </div>
                </ItemTemplate>
            </asp:ListView>
    
                        </td>
                </tr>
                <tr>
                    <td>
    
                        <br />
                    </td>
                    <td>
                         </td>
                </tr>
            </table>
        
        </div>
        </form>
    </body>
    </html>

    Отметим, что элемент управления, при помощи которого мы будем отображать имеющиеся изображения - это ListView с идентификатором lv_images. Для того чтобы сделать возможным повторени вышеуказанного шаблона для каждого элемента списка мы использовали Repeater (подробнее см. в списке вспомогательных материалов)

    Теперь в метод Page_Load добавим код, который при первой загрузке нашей страницы будет проверять наличие контейнера и выводить сообщение о возможных ошибках и привязывать lv_images к источнику данных, вызовом метода RefreshGallery:

    try
                {
                    if (!IsPostBack)
                    {
                        this.EnsureContainerExists();
                    }
                    this.RefreshGallery();
                }
                catch (System.Net.WebException we)
                {
                    lb_status.Text = "Network error: " + we.Message;
                    if (we.Status == System.Net.WebExceptionStatus.ConnectFailure)
                    {
                        lb_status.Text += "<br />Please check if the blob service is running at " +
                        ConfigurationManager.AppSettings["storageEndpoint"];
                    }
                }
                catch (StorageException se)
                {
                    Console.WriteLine("Storage service error: " + se.Message);
                }

    Метод RefreshGallery - привязывает lv_images к источнику данных(контейнеру бинарных объектов):

    private void RefreshGallery()
            {
                lv_images.DataSource =
                  this.GetContainer().ListBlobs(new BlobRequestOptions()
                  {
                      UseFlatBlobListing = true,
                      BlobListingDetails = BlobListingDetails.All
                  });
                lv_images.DataBind();
            }

    Запустим приложение и убедимся, что оно выполняется верно.

    (рис 20.4)

    Задание 2. Загрузка изображений

    Необходимо добавить следующую ссылку в AzureBlobSample.cs:

    using System.Collections.Specialized;

    Создадим метод, сохраняющий бинарный объект и задающий его метаданные:

    private void SaveImage(string id, string name, string description, string tags, 
      string fileName, string contentType, byte[] data)
            {
                // Создание BLob - объекта в контейнере
                var blob = this.GetContainer().GetBlobReference(name);
                blob.Properties.ContentType = contentType;
                // определение метаданных, добавление метаданных blob-объекту и загрузка данных
                try
                {
                    blob.UploadFromStream(fu_upload.FileContent);
                    blob.Metadata["Id"] = id;
                    blob.Metadata["Filename"] = fileName;
                    blob.Metadata["ImageName"] = String.IsNullOrEmpty(name) ? "unknown" : name;
                    blob.Metadata["Description"] = String.IsNullOrEmpty(description) ? "unknown" : description;
                    blob.SetMetadata();
                    lv_images.DataBind();
                }
                catch (Exception ex)
                { lb_status.Text = ex.Message; }
            }
            }

    Остается только написать метод - обрабатывающий событие нажатия кнопки btn_upload:

    protected void btn_upload_Click(object sender, EventArgs e)
            {
                if (fu_upload.HasFile)
                  {
                      lb_status.Text = "Inserted [" + fu_upload.FileName + "] - 
                       Content Type [" + fu_upload.PostedFile.ContentType + "] - 
                       Length [" + fu_upload.PostedFile.ContentLength + "]";
                      this.SaveImage(Guid.NewGuid().ToString(),
                        tb_name.Text,
                        tb_desc.Text,
                        fu_upload.FileName,
                        fu_upload.PostedFile.ContentType,
                        fu_upload.FileBytes
                      );
                      RefreshGallery();
                    }
                    else
                      lb_status.Text = "No image file";
               }

    Теперь можно проверить функцию загрузки изображения, выбрав его через диалог загрузки файла.

    (рис 20.5)

    Надо сказать, что в таком виде информация об изображении малоинформативная. Blob, как мы знаем, может хранить привязанные к нему метаданные. Добавим в наше решение функционал, позволяющий получать и отображать метаданные, ассоциированные с конкретным изображением.

    Для начала, необходимо создать метод обрабатывающий событие ItemDataBound элемента управления lv_images:

    protected void lv_images_ItemDataBound(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 (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)
                        {
                            metadataRepeater.DataSource = from key in blob.Metadata.AllKeys
                                                          select new
                                                          {
                                                              Name = key,
                                                              Value = blob.Metadata[key]
                                                          };
                            metadataRepeater.DataBind();
                        }
                    }
                }
            }

    Теперь запустим наше приложение и получим следующее:

    (рис 20.6)

    Слева от изображения появился список метаданных.

    Задание 3 Удаление сущностей

    Для начала необходимо добавить следующий asp - код для lv_images:

    ...
    div class="item">
                        <ul style="width:40em;float:left;clear:left" >
                            <asp:Repeater ID="blobMetadata" runat="server">
                            <ItemTemplate>
                                <li><%# Eval("Name") %><span><%# Eval("Value") %></span></li>
                            </ItemTemplate>
                            </asp:Repeater>
                            <li>
                                <asp:LinkButton ID="deleteBlob" 
                                        OnClientClick="return confirm('Delete image?');"
                                        CommandName="Delete" 
                                        CommandArgument='<%# Eval("Uri")%>'
                                        runat="server" Text="Удалить" oncommand="OnDeleteImage" />
    ...

    Это необходимо для формировании кнопки "Delete" в рамках нашего ListView. Кроме того, этот кол содержит ссылку на метод, выполняющийся при нажатии кнопки.

    Метод OnDeleteImage:

    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();
                    }
                }
                catch (StorageClientException se)
                {
                    lb_status.Text = "Storage client error: " + se.Message;
                }
                catch (Exception) { }
                RefreshGallery();
            }

    Данный метод определяет бинарный объект и удаляет его.

    Запустите приложение и протестируйте функцию удаления.

    (рис 20.7)

    Задание 4 Копирование сущностей

    Копирование бинарных объектов также поддерживается Windows Azure. В рамках данного задания мы рассмотрим этот механизм.

    Для формирования кнопки "Копировать" в списке имеющихся изображений, добавим следующий asp - код для lv_images :

    ...
                    <div class="item">
                        <ul style="width:40em;float:left;clear:left" >
                            <asp:Repeater ID="blobMetadata" runat="server">
                            <ItemTemplate>
                                <li><%# Eval("Name") %><span><%# Eval("Value") %></span></li>
                            </ItemTemplate>
                            </asp:Repeater>
                            <li>
    ...
    <asp:LinkButton ID="CopyBlob" 
                                        OnClientClick="return confirm('Copy image?');"
                                        CommandName="Copy" 
                                        CommandArgument='<%# Eval("Uri")%>'
                                        runat="server" Text="Copy" oncommand="OnCopyImage" />
    ...

    Как и в предыдущем задании, создадим метод OnCopyImage:

    protected void OnCopyImage(object sender, CommandEventArgs e)
            {
                if (e.CommandName == "Copy")
                {
                    // Prepare an Id for the copied blob
                    var newId = Guid.NewGuid();
                    // получение исходного объекта
                    var blobUri = (string)e.CommandArgument;
                    var srcBlob = this.GetContainer().GetBlobReference(blobUri);
                    // создание нового бинарного объекта
                    var newBlob = this.GetContainer().GetBlobReference(newId.ToString());
                    // копирование содержимого исходного объекта
                    newBlob.CopyFromBlob(srcBlob);
                    // получаем метаданные для нового объекта
                    newBlob.FetchAttributes(new BlobRequestOptions { BlobListingDetails = BlobListingDetails.Metadata });
                    // изменение метаданных нового объекта, чтобы показать, что это копия
                    newBlob.Metadata["ImageName"] = "Copy of \"" + newBlob.Metadata["ImageName"] 
                       + "\"";
                    newBlob.Metadata["Id"] = newId.ToString();
                    newBlob.SetMetadata();
                    RefreshGallery();
                }
            }

    Проверим функционал:

    (рис 20.8)

    В случае, если выполнение задания вызвало сложности и затруднения, в приложениях к данной практической работе вы найдете итоговый программный код в том виде, в котором он необходим для последнего задания.

    Список вспомогательных материалов

    Работа с Windows Azure Blob

  • http://msdn.microsoft.com/en-us/wazplatformtrainingcourse_exploringwindowsazurestoragevs2010_topic3
  • http://blogs.msdn.com/b/jnak/archive/2010/01/11/walkthrough-windows-azure-blob-storage-nov-2009-and-later.aspx
  • http://blogs.msdn.com/b/jnak/archive/2008/10/29/walkthrough-simple-blob-storage-sample.aspx
  • http://wotudo.net/blogs/wotudo/archive/2010/02/16/copying-files-to-windows-azure-blob-storage.aspx
  • Repeater

  • http://msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.repeater.aspx
  • http://www.w3schools.com/ASPNET/aspnet_repeater.asp
  • http://articles.sitepoint.com/article/asp-net-repeater-control
  • Приложение А asp - код страницы AzureBlobSample.aspx

    <%@ Page Language="C#" AutoEventWireup="true" 
      CodeBehind="AzureBlobSample.aspx.cs" Inherits="WebRole1.AzureBlobSample" %> 
      
     <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
      
     <html xmlns="http://www.w3.org/1999/xhtml"> 
     <head runat="server"> 
         <title></title> 
         <style type="text/css"> 
             .style1 
             { 
                 height: 25px; 
             } 
         </style> 
     </head> 
     <body> 
         <form id="form1" runat="server"> 
         <div> 
          
             <asp:Label ID="Label1" runat="server" Font-Bold="True" Font-Size="X-Large"  
                 Text="My Image Gallery - Azure Blob Example"></asp:Label> 
             <br /> 
             <br /> 
             <table style="width:100%;"> 
                 <tr> 
                     <td> 
                         <asp:Label ID="lb_name" runat="server" Text="Название"></asp:Label> 
                     </td> 
                     <td> 
                         <asp:TextBox ID="tb_name" runat="server"></asp:TextBox> 
                     </td> 
                 </tr> 
                 <tr> 
                     <td> 
                         <asp:Label ID="lb_desc" runat="server" Text="Описание"></asp:Label> 
                     </td> 
                     <td> 
                         <asp:TextBox ID="tb_desc" runat="server"></asp:TextBox> 
                     </td> 
                 </tr> 
                 <tr> 
                     <td> 
                          </td> 
                     <td> 
                          </td> 
                 </tr> 
                 <tr> 
                     <td class="style1"> 
                         <asp:Label ID="lb_file" runat="server" Text="Файл"></asp:Label> 
                     </td> 
                     <td class="style1"> 
                         <asp:FileUpload ID="fu_upload" runat="server" /> 
                     </td> 
                 </tr> 
                 <tr> 
                     <td> 
                          </td> 
                     <td> 
                         <asp:Button ID="btn_upload" runat="server" onclick="btn_upload_Click"  
                             Text="Загрузить" /> 
                     </td> 
                 </tr> 
                 <tr> 
                     <td> 
                         <asp:Label ID="lb_status" runat="server"></asp:Label> 
                     </td> 
                     <td> 
                          </td> 
                 </tr> 
                 <tr> 
                     <td> 
                          </td> 
                     <td> 
                         <asp:ListView ID="lv_images" runat="server"  
                             onitemdatabound="lv_images_ItemDataBound"> 
                 <LayoutTemplate> 
                     <asp:PlaceHolder ID="itemPlaceholder" runat="server" /> 
                 </LayoutTemplate> 
                 <EmptyDataTemplate> 
                     <h2>No Data Available</h2> 
                 </EmptyDataTemplate> 
                 <ItemTemplate>             
                     <div class="item"> 
                         <ul style="width:40em;float:left;clear:left" > 
                             <asp:Repeater ID="blobMetadata" runat="server"> 
                             <ItemTemplate> 
                                 <li><%# Eval("Name") %><span><%# Eval("Value") %></span></li> 
                             </ItemTemplate> 
                             </asp:Repeater> 
                             <li> 
                                 <asp:LinkButton ID="deleteBlob"  
                                         OnClientClick="return confirm('Delete image?');" 
                                         CommandName="Delete"  
                                         CommandArgument='<%# Eval("Uri")%>' 
                                         runat="server" Text="Удалить" oncommand="OnDeleteImage" /> 
      
                                 <asp:LinkButton ID="CopyBlob"  
                                         OnClientClick="return confirm('Copy image?');" 
                                         CommandName="Copy"  
                                         CommandArgument='<%# Eval("Uri")%>' 
                                         runat="server" Text="Копировать" oncommand="OnCopyImage" /> 
      
                             </li> 
                         </ul> 
                         <img src="<%# Eval("Uri") %>" alt="<%# Eval("Uri") %>" style="float:left"/> 
                     </div> 
                 </ItemTemplate> 
             </asp:ListView> 
      
                         </td> 
                 </tr> 
                 <tr> 
                     <td> 
      
                         <br /> 
                     </td> 
                     <td> 
                          </td> 
                 </tr> 
             </table> 
          
         </div> 
         </form> 
     </body> 
     </html>

    Приложение Б AzureBlobSample.aspx.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.ServiceRuntime;
    using Microsoft.WindowsAzure.StorageClient;
    using System.Configuration;
    using System.Collections.Specialized;
    
    namespace WebRole1
    {
        public partial class AzureBlobSample : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                try
                {
                    if (!IsPostBack)
                    {
                        this.EnsureContainerExists();
                    }
                    this.RefreshGallery();
                }
                catch (System.Net.WebException we)
                {
                    lb_status.Text = "Network error: " + we.Message;
                    if (we.Status == System.Net.WebExceptionStatus.ConnectFailure)
                    {
                        lb_status.Text += "<br />Please check if the blob service is running at " +
                        ConfigurationManager.AppSettings["storageEndpoint"];
                    }
                }
                catch (StorageException se)
                {
                    Console.WriteLine("Storage service error: " + se.Message);
                }
    
            }
    
            private void RefreshGallery()
            {
                lv_images.DataSource =
                  this.GetContainer().ListBlobs(new BlobRequestOptions()
                  {
                      UseFlatBlobListing = true,
                      BlobListingDetails = BlobListingDetails.All
                  });
                lv_images.DataBind();
            }
    
            private CloudBlobContainer GetContainer()
            {
                CloudStorageAccount.SetConfigurationSettingPublisher(
                    (configName, configSettingPublisher) =>
                    {
                        var connectionString =
                            RoleEnvironment.GetConfigurationSettingValue(configName);
                        configSettingPublisher(connectionString);
                    }
                );
    
                var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
                var client = account.CreateCloudBlobClient();
                return client.GetContainerReference(RoleEnvironment.GetConfigurationSettingValue("ContainerName"));
            }
    
            private void EnsureContainerExists()
            {
                var container = GetContainer();
                container.CreateIfNotExist();
                var permissions = container.GetPermissions();
                permissions.PublicAccess = BlobContainerPublicAccessType.Container;
                container.SetPermissions(permissions);
            }
    
            private void SaveImage(string id, string name, string description, string fileName, string contentType, byte[] data)
            {
                var blob = this.GetContainer().GetBlobReference(name);
                blob.Properties.ContentType = contentType;
                
                try
                {
                    blob.UploadFromStream(fu_upload.FileContent);
                    blob.Metadata["Id"] = id;
                    blob.Metadata["Filename"] = fileName;
                    blob.Metadata["ImageName"] = String.IsNullOrEmpty(name) ? "unknown" : name;
                    blob.Metadata["Description"] = String.IsNullOrEmpty(description) ? "unknown" : description;
                    blob.SetMetadata();
                    lv_images.DataBind();
                }
                catch (Exception ex)
                { lb_status.Text = ex.Message; }
            }
    
            protected void btn_upload_Click(object sender, EventArgs e)
            {
                if (fu_upload.HasFile)
                  {
                      lb_status.Text = "Inserted [" + fu_upload.FileName + "] - Content Type [" + 
                      fu_upload.PostedFile.ContentType + "] - Length [" + fu_upload.PostedFile.ContentLength + "]";
                      this.SaveImage(Guid.NewGuid().ToString(),
                        tb_name.Text,
                        tb_desc.Text,
                        fu_upload.FileName,
                        fu_upload.PostedFile.ContentType,
                        fu_upload.FileBytes
                      );
                      RefreshGallery();
                    }
                    else
                      lb_status.Text = "No image file";
               }
    
            protected void lv_images_ItemDataBound(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 (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)
                        {
                            metadataRepeater.DataSource = from key in blob.Metadata.AllKeys
                                                          select new
                                                          {
                                                              Name = key,
                                                              Value = blob.Metadata[key]
                                                          };
                            metadataRepeater.DataBind();
                        }
                    }
                }
            }
    
            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();
                    }
                }
                catch (StorageClientException se)
                {
                    lb_status.Text = "Storage client error: " + se.Message;
                }
                catch (Exception) { }
                RefreshGallery();
            }
    
    
            protected void OnCopyImage(object sender, CommandEventArgs e)
            {
                if (e.CommandName == "Copy")
                {
                    // Prepare an Id for the copied blob
                    var newId = Guid.NewGuid();
                    // получение исходного объекта
                    var blobUri = (string)e.CommandArgument;
                    var srcBlob = this.GetContainer().GetBlobReference(blobUri);
                    // создание нового бинарного объекта
                    var newBlob = this.GetContainer().GetBlobReference(newId.ToString());
                    // копирование содержимого исходного объекта
                    newBlob.CopyFromBlob(srcBlob);
                    // получаем метаданные для нового объекта
                    newBlob.FetchAttributes(new BlobRequestOptions { BlobListingDetails = BlobListingDetails.Metadata });
                    // изменение метаданных нового объекта, чтобы показать, что это копия
                    newBlob.Metadata["ImageName"] = "Copy of \"" + 
                      newBlob.Metadata["ImageName"] + "\"";
                    newBlob.Metadata["Id"] = newId.ToString();
                    newBlob.SetMetadata();
                    RefreshGallery();
                }
            }
                 
        }
    }
    Страницы:

    В качестве примера рассмотрим работу простого веб - приложения для загрузки изображений в хранилище Windows Azure Blob:

  • подготовка приложения;
  • загрузка и отображение изображений;
  • удаление сущностей;
  • копирование сущностей.
  • Создайте проект облачной службы и добавьте веб - роль в решение.

    В свойствах веб - роли определим строку подключения к эмулятору хранилища Azure.

    (рис 20.1)

    Также нам понадобится строковый параметр ContainerName, определяющий имя Blob - контейнера для изображений.

    (рис 20.2)

    Задание 1. Подготовка приложени

    Создадим веб - форму AzureBlobSamle.aspx и добавим ссылки в C# класс данной страницы

    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.ServiceRuntime;
    using Microsoft.WindowsAzure.StorageClient;
    using System.Configuration;

    Далее, поскольку Blob - контейнер должен быть доступным для анонимных пользователей необходимо создать метод, подтверждающий наличие контейнера:

    private void EnsureContainerExists()
            {
                var container = GetContainer();
                container.CreateIfNotExist();
                var permissions = container.GetPermissions();
                permissions.PublicAccess = BlobContainerPublicAccessType.Container;
                container.SetPermissions(permissions);
            }

    Как видно, в данном методе присутствует ссылка на несуществующий пока GetConteiner() , который должен возвращать Blob-контейнер для осуществления операций с Blob-объектами.

    private CloudBlobContainer GetContainer()
            {
                CloudStorageAccount.SetConfigurationSettingPublisher(
                    (configName, configSettingPublisher) =>
                    {
                        var connectionString =
                            RoleEnvironment.GetConfigurationSettingValue(configName);
                        configSettingPublisher(connectionString);
                    }
                );
    
                var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
                var client = account.CreateCloudBlobClient();
                return client.GetContainerReference(RoleEnvironment.GetConfigurationSettingValue("ContainerName"));
            }

    Интерфейс

    Теперь необходимо заняться самой формой. На форме буду присутствовать текстовые поля, задающие параметры изображения и диалог загрузки файла.

    (рис 20.3)

    asp - код веб формы:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AzureBlobSample.aspx.cs"
      Inherits="WebRole1.AzureBlobSample" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
        
            <asp:Label ID="Label1" runat="server" Font-Bold="True" Font-Size="X-Large" 
                Text="My Image Gallery - Azure Blob Example"></asp:Label>
            <br />
            <br />
            <table style="width:100%;">
                <tr>
                    <td>
                        <asp:Label ID="lb_name" runat="server" Text="Название"></asp:Label>
                    </td>
                    <td>
                        <asp:TextBox ID="tb_label" runat="server"></asp:TextBox>
                    </td>
                </tr>
                <tr>
                    <td>
                        <asp:Label ID="lb_desc" runat="server" Text="Описание"></asp:Label>
                    </td>
                    <td>
                        <asp:TextBox ID="tb_desc" runat="server"></asp:TextBox>
                    </td>
                </tr>
                <tr>
                    <td>
                         </td>
                    <td>
                         </td>
                </tr>
                <tr>
                    <td>
                        <asp:Label ID="lb_file" runat="server" Text="Файл"></asp:Label>
                    </td>
                    <td>
                        <asp:FileUpload ID="fu_upload" runat="server" />
                    </td>
                </tr>
                <tr>
                    <td>
                         </td>
                    <td>
                        <asp:Button ID="btn_upload" runat="server" onclick="btn_upload_Click" 
                            Text="Загрузить" />
                    </td>
                </tr>
                <tr>
                    <td>
                         </td>
                    <td>
                         </td>
                </tr>
                <tr>
                    <td>
                        <asp:Label ID="lb_status" runat="server"></asp:Label>
                    </td>
                    <td>
                        <asp:ListView ID="lv_images" runat="server">
                <LayoutTemplate>
                    <asp:PlaceHolder ID="itemPlaceholder" runat="server" />
                </LayoutTemplate>
                <EmptyDataTemplate>
                    <h2>No Data Available</h2>
                </EmptyDataTemplate>
                <ItemTemplate>            
                    <div class="item">
                        <ul style="width:40em;float:left;clear:left" >
                            <asp:Repeater ID="blobMetadata" runat="server">
                            <ItemTemplate>
                                <li><%# Eval("Name") %><span><%# Eval("Value") %></span></li>
                            </ItemTemplate>
                            </asp:Repeater>
                            <li>
    
                            </li>
                        </ul>
                        <img src="<%# Eval("Uri") %>" alt="<%# Eval("Uri") %>" style="float:left"/>
                    </div>
                </ItemTemplate>
            </asp:ListView>
    
                        </td>
                </tr>
                <tr>
                    <td>
    
                        <br />
                    </td>
                    <td>
                         </td>
                </tr>
            </table>
        
        </div>
        </form>
    </body>
    </html>

    Отметим, что элемент управления, при помощи которого мы будем отображать имеющиеся изображения - это ListView с идентификатором lv_images. Для того чтобы сделать возможным повторени вышеуказанного шаблона для каждого элемента списка мы использовали Repeater (подробнее см. в списке вспомогательных материалов)

    Теперь в метод Page_Load добавим код, который при первой загрузке нашей страницы будет проверять наличие контейнера и выводить сообщение о возможных ошибках и привязывать lv_images к источнику данных, вызовом метода RefreshGallery:

    try
                {
                    if (!IsPostBack)
                    {
                        this.EnsureContainerExists();
                    }
                    this.RefreshGallery();
                }
                catch (System.Net.WebException we)
                {
                    lb_status.Text = "Network error: " + we.Message;
                    if (we.Status == System.Net.WebExceptionStatus.ConnectFailure)
                    {
                        lb_status.Text += "<br />Please check if the blob service is running at " +
                        ConfigurationManager.AppSettings["storageEndpoint"];
                    }
                }
                catch (StorageException se)
                {
                    Console.WriteLine("Storage service error: " + se.Message);
                }

    Метод RefreshGallery - привязывает lv_images к источнику данных(контейнеру бинарных объектов):

    private void RefreshGallery()
            {
                lv_images.DataSource =
                  this.GetContainer().ListBlobs(new BlobRequestOptions()
                  {
                      UseFlatBlobListing = true,
                      BlobListingDetails = BlobListingDetails.All
                  });
                lv_images.DataBind();
            }

    Запустим приложение и убедимся, что оно выполняется верно.

    (рис 20.4)

    Задание 2. Загрузка изображений

    Необходимо добавить следующую ссылку в AzureBlobSample.cs:

    using System.Collections.Specialized;

    Создадим метод, сохраняющий бинарный объект и задающий его метаданные:

    private void SaveImage(string id, string name, string description, string tags, 
      string fileName, string contentType, byte[] data)
            {
                // Создание BLob - объекта в контейнере
                var blob = this.GetContainer().GetBlobReference(name);
                blob.Properties.ContentType = contentType;
                // определение метаданных, добавление метаданных blob-объекту и загрузка данных
                try
                {
                    blob.UploadFromStream(fu_upload.FileContent);
                    blob.Metadata["Id"] = id;
                    blob.Metadata["Filename"] = fileName;
                    blob.Metadata["ImageName"] = String.IsNullOrEmpty(name) ? "unknown" : name;
                    blob.Metadata["Description"] = String.IsNullOrEmpty(description) ? "unknown" : description;
                    blob.SetMetadata();
                    lv_images.DataBind();
                }
                catch (Exception ex)
                { lb_status.Text = ex.Message; }
            }
            }

    Остается только написать метод - обрабатывающий событие нажатия кнопки btn_upload:

    protected void btn_upload_Click(object sender, EventArgs e)
            {
                if (fu_upload.HasFile)
                  {
                      lb_status.Text = "Inserted [" + fu_upload.FileName + "] - 
                       Content Type [" + fu_upload.PostedFile.ContentType + "] - 
                       Length [" + fu_upload.PostedFile.ContentLength + "]";
                      this.SaveImage(Guid.NewGuid().ToString(),
                        tb_name.Text,
                        tb_desc.Text,
                        fu_upload.FileName,
                        fu_upload.PostedFile.ContentType,
                        fu_upload.FileBytes
                      );
                      RefreshGallery();
                    }
                    else
                      lb_status.Text = "No image file";
               }

    Теперь можно проверить функцию загрузки изображения, выбрав его через диалог загрузки файла.

    (рис 20.5)

    Надо сказать, что в таком виде информация об изображении малоинформативная. Blob, как мы знаем, может хранить привязанные к нему метаданные. Добавим в наше решение функционал, позволяющий получать и отображать метаданные, ассоциированные с конкретным изображением.

    Для начала, необходимо создать метод обрабатывающий событие ItemDataBound элемента управления lv_images:

    protected void lv_images_ItemDataBound(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 (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)
                        {
                            metadataRepeater.DataSource = from key in blob.Metadata.AllKeys
                                                          select new
                                                          {
                                                              Name = key,
                                                              Value = blob.Metadata[key]
                                                          };
                            metadataRepeater.DataBind();
                        }
                    }
                }
            }

    Теперь запустим наше приложение и получим следующее:

    (рис 20.6)

    Слева от изображения появился список метаданных.

    Задание 3 Удаление сущностей

    Для начала необходимо добавить следующий asp - код для lv_images:

    ...
    div class="item">
                        <ul style="width:40em;float:left;clear:left" >
                            <asp:Repeater ID="blobMetadata" runat="server">
                            <ItemTemplate>
                                <li><%# Eval("Name") %><span><%# Eval("Value") %></span></li>
                            </ItemTemplate>
                            </asp:Repeater>
                            <li>
                                <asp:LinkButton ID="deleteBlob" 
                                        OnClientClick="return confirm('Delete image?');"
                                        CommandName="Delete" 
                                        CommandArgument='<%# Eval("Uri")%>'
                                        runat="server" Text="Удалить" oncommand="OnDeleteImage" />
    ...

    Это необходимо для формировании кнопки "Delete" в рамках нашего ListView. Кроме того, этот кол содержит ссылку на метод, выполняющийся при нажатии кнопки.

    Метод OnDeleteImage:

    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();
                    }
                }
                catch (StorageClientException se)
                {
                    lb_status.Text = "Storage client error: " + se.Message;
                }
                catch (Exception) { }
                RefreshGallery();
            }

    Данный метод определяет бинарный объект и удаляет его.

    Запустите приложение и протестируйте функцию удаления.

    (рис 20.7)

    Задание 4 Копирование сущностей

    Копирование бинарных объектов также поддерживается Windows Azure. В рамках данного задания мы рассмотрим этот механизм.

    Для формирования кнопки "Копировать" в списке имеющихся изображений, добавим следующий asp - код для lv_images :

    ...
                    <div class="item">
                        <ul style="width:40em;float:left;clear:left" >
                            <asp:Repeater ID="blobMetadata" runat="server">
                            <ItemTemplate>
                                <li><%# Eval("Name") %><span><%# Eval("Value") %></span></li>
                            </ItemTemplate>
                            </asp:Repeater>
                            <li>
    ...
    <asp:LinkButton ID="CopyBlob" 
                                        OnClientClick="return confirm('Copy image?');"
                                        CommandName="Copy" 
                                        CommandArgument='<%# Eval("Uri")%>'
                                        runat="server" Text="Copy" oncommand="OnCopyImage" />
    ...

    Как и в предыдущем задании, создадим метод OnCopyImage:

    protected void OnCopyImage(object sender, CommandEventArgs e)
            {
                if (e.CommandName == "Copy")
                {
                    // Prepare an Id for the copied blob
                    var newId = Guid.NewGuid();
                    // получение исходного объекта
                    var blobUri = (string)e.CommandArgument;
                    var srcBlob = this.GetContainer().GetBlobReference(blobUri);
                    // создание нового бинарного объекта
                    var newBlob = this.GetContainer().GetBlobReference(newId.ToString());
                    // копирование содержимого исходного объекта
                    newBlob.CopyFromBlob(srcBlob);
                    // получаем метаданные для нового объекта
                    newBlob.FetchAttributes(new BlobRequestOptions { BlobListingDetails = BlobListingDetails.Metadata });
                    // изменение метаданных нового объекта, чтобы показать, что это копия
                    newBlob.Metadata["ImageName"] = "Copy of \"" + newBlob.Metadata["ImageName"] 
                       + "\"";
                    newBlob.Metadata["Id"] = newId.ToString();
                    newBlob.SetMetadata();
                    RefreshGallery();
                }
            }

    Проверим функционал:

    (рис 20.8)

    В случае, если выполнение задания вызвало сложности и затруднения, в приложениях к данной практической работе вы найдете итоговый программный код в том виде, в котором он необходим для последнего задания.

    Список вспомогательных материалов

    Работа с Windows Azure Blob

  • http://msdn.microsoft.com/en-us/wazplatformtrainingcourse_exploringwindowsazurestoragevs2010_topic3
  • http://blogs.msdn.com/b/jnak/archive/2010/01/11/walkthrough-windows-azure-blob-storage-nov-2009-and-later.aspx
  • http://blogs.msdn.com/b/jnak/archive/2008/10/29/walkthrough-simple-blob-storage-sample.aspx
  • http://wotudo.net/blogs/wotudo/archive/2010/02/16/copying-files-to-windows-azure-blob-storage.aspx
  • Repeater

  • http://msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.repeater.aspx
  • http://www.w3schools.com/ASPNET/aspnet_repeater.asp
  • http://articles.sitepoint.com/article/asp-net-repeater-control
  • Приложение А asp - код страницы AzureBlobSample.aspx

    <%@ Page Language="C#" AutoEventWireup="true" 
      CodeBehind="AzureBlobSample.aspx.cs" Inherits="WebRole1.AzureBlobSample" %> 
      
     <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
      
     <html xmlns="http://www.w3.org/1999/xhtml"> 
     <head runat="server"> 
         <title></title> 
         <style type="text/css"> 
             .style1 
             { 
                 height: 25px; 
             } 
         </style> 
     </head> 
     <body> 
         <form id="form1" runat="server"> 
         <div> 
          
             <asp:Label ID="Label1" runat="server" Font-Bold="True" Font-Size="X-Large"  
                 Text="My Image Gallery - Azure Blob Example"></asp:Label> 
             <br /> 
             <br /> 
             <table style="width:100%;"> 
                 <tr> 
                     <td> 
                         <asp:Label ID="lb_name" runat="server" Text="Название"></asp:Label> 
                     </td> 
                     <td> 
                         <asp:TextBox ID="tb_name" runat="server"></asp:TextBox> 
                     </td> 
                 </tr> 
                 <tr> 
                     <td> 
                         <asp:Label ID="lb_desc" runat="server" Text="Описание"></asp:Label> 
                     </td> 
                     <td> 
                         <asp:TextBox ID="tb_desc" runat="server"></asp:TextBox> 
                     </td> 
                 </tr> 
                 <tr> 
                     <td> 
                          </td> 
                     <td> 
                          </td> 
                 </tr> 
                 <tr> 
                     <td class="style1"> 
                         <asp:Label ID="lb_file" runat="server" Text="Файл"></asp:Label> 
                     </td> 
                     <td class="style1"> 
                         <asp:FileUpload ID="fu_upload" runat="server" /> 
                     </td> 
                 </tr> 
                 <tr> 
                     <td> 
                          </td> 
                     <td> 
                         <asp:Button ID="btn_upload" runat="server" onclick="btn_upload_Click"  
                             Text="Загрузить" /> 
                     </td> 
                 </tr> 
                 <tr> 
                     <td> 
                         <asp:Label ID="lb_status" runat="server"></asp:Label> 
                     </td> 
                     <td> 
                          </td> 
                 </tr> 
                 <tr> 
                     <td> 
                          </td> 
                     <td> 
                         <asp:ListView ID="lv_images" runat="server"  
                             onitemdatabound="lv_images_ItemDataBound"> 
                 <LayoutTemplate> 
                     <asp:PlaceHolder ID="itemPlaceholder" runat="server" /> 
                 </LayoutTemplate> 
                 <EmptyDataTemplate> 
                     <h2>No Data Available</h2> 
                 </EmptyDataTemplate> 
                 <ItemTemplate>             
                     <div class="item"> 
                         <ul style="width:40em;float:left;clear:left" > 
                             <asp:Repeater ID="blobMetadata" runat="server"> 
                             <ItemTemplate> 
                                 <li><%# Eval("Name") %><span><%# Eval("Value") %></span></li> 
                             </ItemTemplate> 
                             </asp:Repeater> 
                             <li> 
                                 <asp:LinkButton ID="deleteBlob"  
                                         OnClientClick="return confirm('Delete image?');" 
                                         CommandName="Delete"  
                                         CommandArgument='<%# Eval("Uri")%>' 
                                         runat="server" Text="Удалить" oncommand="OnDeleteImage" /> 
      
                                 <asp:LinkButton ID="CopyBlob"  
                                         OnClientClick="return confirm('Copy image?');" 
                                         CommandName="Copy"  
                                         CommandArgument='<%# Eval("Uri")%>' 
                                         runat="server" Text="Копировать" oncommand="OnCopyImage" /> 
      
                             </li> 
                         </ul> 
                         <img src="<%# Eval("Uri") %>" alt="<%# Eval("Uri") %>" style="float:left"/> 
                     </div> 
                 </ItemTemplate> 
             </asp:ListView> 
      
                         </td> 
                 </tr> 
                 <tr> 
                     <td> 
      
                         <br /> 
                     </td> 
                     <td> 
                          </td> 
                 </tr> 
             </table> 
          
         </div> 
         </form> 
     </body> 
     </html>

    Приложение Б AzureBlobSample.aspx.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.ServiceRuntime;
    using Microsoft.WindowsAzure.StorageClient;
    using System.Configuration;
    using System.Collections.Specialized;
    
    namespace WebRole1
    {
        public partial class AzureBlobSample : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                try
                {
                    if (!IsPostBack)
                    {
                        this.EnsureContainerExists();
                    }
                    this.RefreshGallery();
                }
                catch (System.Net.WebException we)
                {
                    lb_status.Text = "Network error: " + we.Message;
                    if (we.Status == System.Net.WebExceptionStatus.ConnectFailure)
                    {
                        lb_status.Text += "<br />Please check if the blob service is running at " +
                        ConfigurationManager.AppSettings["storageEndpoint"];
                    }
                }
                catch (StorageException se)
                {
                    Console.WriteLine("Storage service error: " + se.Message);
                }
    
            }
    
            private void RefreshGallery()
            {
                lv_images.DataSource =
                  this.GetContainer().ListBlobs(new BlobRequestOptions()
                  {
                      UseFlatBlobListing = true,
                      BlobListingDetails = BlobListingDetails.All
                  });
                lv_images.DataBind();
            }
    
            private CloudBlobContainer GetContainer()
            {
                CloudStorageAccount.SetConfigurationSettingPublisher(
                    (configName, configSettingPublisher) =>
                    {
                        var connectionString =
                            RoleEnvironment.GetConfigurationSettingValue(configName);
                        configSettingPublisher(connectionString);
                    }
                );
    
                var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
                var client = account.CreateCloudBlobClient();
                return client.GetContainerReference(RoleEnvironment.GetConfigurationSettingValue("ContainerName"));
            }
    
            private void EnsureContainerExists()
            {
                var container = GetContainer();
                container.CreateIfNotExist();
                var permissions = container.GetPermissions();
                permissions.PublicAccess = BlobContainerPublicAccessType.Container;
                container.SetPermissions(permissions);
            }
    
            private void SaveImage(string id, string name, string description, string fileName, string contentType, byte[] data)
            {
                var blob = this.GetContainer().GetBlobReference(name);
                blob.Properties.ContentType = contentType;
                
                try
                {
                    blob.UploadFromStream(fu_upload.FileContent);
                    blob.Metadata["Id"] = id;
                    blob.Metadata["Filename"] = fileName;
                    blob.Metadata["ImageName"] = String.IsNullOrEmpty(name) ? "unknown" : name;
                    blob.Metadata["Description"] = String.IsNullOrEmpty(description) ? "unknown" : description;
                    blob.SetMetadata();
                    lv_images.DataBind();
                }
                catch (Exception ex)
                { lb_status.Text = ex.Message; }
            }
    
            protected void btn_upload_Click(object sender, EventArgs e)
            {
                if (fu_upload.HasFile)
                  {
                      lb_status.Text = "Inserted [" + fu_upload.FileName + "] - Content Type [" + 
                      fu_upload.PostedFile.ContentType + "] - Length [" + fu_upload.PostedFile.ContentLength + "]";
                      this.SaveImage(Guid.NewGuid().ToString(),
                        tb_name.Text,
                        tb_desc.Text,
                        fu_upload.FileName,
                        fu_upload.PostedFile.ContentType,
                        fu_upload.FileBytes
                      );
                      RefreshGallery();
                    }
                    else
                      lb_status.Text = "No image file";
               }
    
            protected void lv_images_ItemDataBound(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 (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)
                        {
                            metadataRepeater.DataSource = from key in blob.Metadata.AllKeys
                                                          select new
                                                          {
                                                              Name = key,
                                                              Value = blob.Metadata[key]
                                                          };
                            metadataRepeater.DataBind();
                        }
                    }
                }
            }
    
            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();
                    }
                }
                catch (StorageClientException se)
                {
                    lb_status.Text = "Storage client error: " + se.Message;
                }
                catch (Exception) { }
                RefreshGallery();
            }
    
    
            protected void OnCopyImage(object sender, CommandEventArgs e)
            {
                if (e.CommandName == "Copy")
                {
                    // Prepare an Id for the copied blob
                    var newId = Guid.NewGuid();
                    // получение исходного объекта
                    var blobUri = (string)e.CommandArgument;
                    var srcBlob = this.GetContainer().GetBlobReference(blobUri);
                    // создание нового бинарного объекта
                    var newBlob = this.GetContainer().GetBlobReference(newId.ToString());
                    // копирование содержимого исходного объекта
                    newBlob.CopyFromBlob(srcBlob);
                    // получаем метаданные для нового объекта
                    newBlob.FetchAttributes(new BlobRequestOptions { BlobListingDetails = BlobListingDetails.Metadata });
                    // изменение метаданных нового объекта, чтобы показать, что это копия
                    newBlob.Metadata["ImageName"] = "Copy of \"" + 
                      newBlob.Metadata["ImageName"] + "\"";
                    newBlob.Metadata["Id"] = newId.ToString();
                    newBlob.SetMetadata();
                    RefreshGallery();
                }
            }
                 
        }
    }
    Вернуться к учебному плану