ブロブストレージを使う

Windows Azure入門のp119からのサンプルを最新のSDKに置き換えてみます。

まずは、Cloud Serviceプロジェクトを新規作成します。次に、
ServiceDefinition.csdefの編集。

<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="PhotoList" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
  <WebRole name="PhotoList_WebRole">
    <InputEndpoints>
      <InputEndpoint name="HttpIn" protocol="http" port="80" />
    </InputEndpoints>
    <ConfigurationSettings>
      <Setting name="DiagnosticsConnectionString" />
      <Setting name="DataConnectionString" />
    </ConfigurationSettings>
  </WebRole>
</ServiceDefinition>

上記のようにDataConnectionStringを追加します。

ServiceConfiguration.cscfgの編集。

<?xml version="1.0"?>
<ServiceConfiguration serviceName="PhotoList" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration">
  <Role name="PhotoList_WebRole">
    <Instances count="1" />
    <ConfigurationSettings>
      <Setting name="DiagnosticsConnectionString" value="UseDevelopmentStorage=true" />
      <Setting name="DataConnectionString" value="UseDevelopmentStorage=true" />
    </ConfigurationSettings>
  </Role>
</ServiceConfiguration>

DataConnectionStringの値を開発用ストレージを使うようにします。

WebRole.csの編集。

using System.Linq;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure;

namespace PhotoList_WebRole
{
    public class WebRole : RoleEntryPoint
    {
        public override bool OnStart()
        {
            DiagnosticMonitor.Start("DiagnosticsConnectionString");

            // For information on handling configuration changes
            // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.

            #region Setup CloudStorageAccount Configuration Setting Publisher

            // This code sets up a handler to update CloudStorageAccount instances when their corresponding
            // configuration settings change in the service configuration file.
            CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
            {
                // Provide the configSetter with the initial value
                var setting = RoleEnvironment.GetConfigurationSettingValue(configName);
                configSetter(setting);

                RoleEnvironment.Changed += (sender, arg) =>
                {
                    if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
                        .Any((change) => (change.ConfigurationSettingName == configName)))
                    {
                        // The corresponding configuration setting has changed, propagate the value
                        if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
                        {
                            // In this case, the change to the storage account credentials in the
                            // service configuration is significant enough that the role needs to be
                            // recycled in order to use the latest settings. (for example, the 
                            // endpoint has changed)
                            RoleEnvironment.RequestRecycle();
                        }
                    }
                };
            });
            #endregion
 
            return base.OnStart();
        }
    }
}

SDKサンプルのコードをそのままコピーしてきました。

Default.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.StorageClient;

namespace PhotoList_WebRole
{
    public partial class _Default : System.Web.UI.Page
    {
        private CloudBlobClient blobStorage;
        private CloudBlobContainer blobContainer;

        protected void Page_Load(object sender, EventArgs e)
        {
            var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
            blobStorage = storageAccount.CreateCloudBlobClient();
            blobContainer = blobStorage.GetContainerReference("photolist");
            blobContainer.CreateIfNotExist();

            // ブロブの共有ポリシーをパブリックにする
            // これをしないと画像を表示できない
            var permissions = blobContainer.GetPermissions();
            permissions.PublicAccess = BlobContainerPublicAccessType.Container;
            blobContainer.SetPermissions(permissions);
        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            // アップロード
            if (FileUpload1.HasFile)
            {
                string uniqueBlobName = String.Format("image_{0}_{1}.jpg", 
                    DateTime.UtcNow.ToString("yyyyMMddHHmss"), Guid.NewGuid().ToString());

                var blob = blobContainer.GetBlobReference(uniqueBlobName);
                blob.Metadata["Title"] = TextBox1.Text;
                blob.UploadFromStream(FileUpload1.FileContent);

                TextBox1.Text = String.Empty;
            }
        }

        protected void Button2_Click(object sender, EventArgs e)
        {
            // 一覧更新
            Reflesh();
        }

        private void Reflesh()
        {
            var blobs =  blobContainer.ListBlobs();
            Repeater1.DataSource = blobs;
            Repeater1.DataBind();
        }
    }
}

上記コードの

var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

ここで.cscfgに定義したキーを引数にメソッドを呼び出すと、WebRole.cs内に書いたラムダ式が呼び出されます。その後の3行でブロブを作成し、最後に権限を与えています。

Button1_Click、Button2_Clickは単純にファイルのアップロードと表示を行っているだけです。UI部分は以下の通り。

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="PhotoList_WebRole._Default" %>

<!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>
        <table>
            <tr>
                <th>画像</th>
                <td><asp:FileUpload ID="FileUpload1" runat="server" /></td>
            </tr>
            <tr>
                <th>タイトル</th>
                <td><asp:TextBox ID="TextBox1" runat="server" /></td>
            </tr>
        </table>
        <asp:Button ID="Button1" Text="アップロード" runat="server" OnClick="Button1_Click" />
        <asp:Button ID="Button2" Text="一覧更新" runat="server" OnClick="Button2_Click" />
        <asp:Repeater ID="Repeater1" runat="server">
            <HeaderTemplate>
                <table border="1">
                    <tr>    
                        <th>Image</th>
                    </tr>
            </HeaderTemplate>
            <ItemTemplate>
                <tr>
                    <td><img src="<%# Eval("Uri") %>" %>" width="100" /></td>
                </tr>
            </ItemTemplate>
            <FooterTemplate>
                </table>
            </FooterTemplate>
        </asp:Repeater>
    </div>
    </form>
</body>
</html>

これでファイルをブロブにアップロードして表示できました。ただ、ブロブのプロパティ取得がうまくできず、今回はパスしました。(^^;