読者です 読者をやめる 読者になる 読者になる

Silverlight と Windows Azure を組み合わせる(2)

はじめに

この記事の続きです。

WebRole プロジェクトに Table 用のクラスを追加

伝票データは Windows Azure Storage Service の Table に保存することにします。
Table にアクセスするために必要なクラスを WebRole プロジェクトに追加。

// Table に保存するデータを表すクラス
public class SlipEntity : TableStorageEntity
{
    public SlipEntity(string partitionKey, string rowKey)
        : base(partitionKey, rowKey)
    {
    }

    public SlipEntity()
        : base()
    {
    }

    public DateTime Date { get; set; }
    public long No { get; set; }
    public string ProductName { get; set; }
    public long Amount { get; set; }
}

// Table を操作するクラス
public class SlipDataServiceContext : TableStorageDataServiceContext
{
    public SlipDataServiceContext(StorageAccountInfo account)
        : base(account)
    {
    }

    public const string SlipTableName = "SlipTable";

    public IQueryable<SlipEntity> SlipTable
    {
        get
        {
            return CreateQuery<SlipEntity>(SlipTableName);
        }
    }
}

WebRole プロジェクトに DataContract を追加

DataContract 属性の付いていないクラスから派生したクラスには、DataContract 属性をつけることが出来ません。その為、先ほどの SlipEntity クラスを DataContract として利用出来ません。
そこで WCF で公開する為のクラスを用意します。この辺はちょっと面倒ですね。

[DataContract]
public class Slip
{
    [DataMember]
    public DateTime Date { get; set; }
    [DataMember]
    public long No { get; set; }
    [DataMember]
    public string ProductName { get; set; }
    [DataMember]
    public long Amount { get; set; }
}

プロパティの名前や型は SlipEntity と揃えています。

WebRole プロジェクトに WCF サービスを追加

[ServiceContract]
public interface ISlipReportService
{
    [OperationContract]
    IEnumerable<Slip> Find(DateTime begin, DateTime end);
}

public class SlipReportService : ISlipReportService
{
    public IEnumerable<Slip> Find(DateTime begin, DateTime end)
    {
        // Table にアクセスするオブジェクトを生成
        StorageAccountInfo account = StorageAccountInfo.GetDefaultTableStorageAccountFromConfiguration();
        SlipDataServiceContext context = new SlipDataServiceContext(account);
        context.RetryPolicy = RetryPolicies.RetryN(3, TimeSpan.FromSeconds(1));

        // クエリで絞り込んでデータ取得
        var linq = from s in context.SlipTable
                   where begin <= s.Date && s.Date <= end
                   select s;
        TableStorageDataServiceQuery<SlipEntity> query = new TableStorageDataServiceQuery<SlipEntity>(
            (DataServiceQuery<SlipEntity>)linq, context.RetryPolicy);
        IEnumerable<SlipEntity> result = query.ExecuteAllWithRetries();

        // SlipEntity を Slip に変換して返す
        List<Slip> slip = new List<Slip>();
        foreach (var entity in result)
        {
            slip.Add(new Slip
            {
                Date = entity.Date,
                No = entity.No,
                ProductName = entity.ProductName,
                Amount = entity.Amount
            });
        }
        return slip;
    }
}

指定した期間内にある伝票データを取得する Find メソッドだけを実装しています。

構成ファイルに必要な情報を記述する

Visual Studio が自動で生成した部分は省略します。

<?xml version="1.0"?>
<configuration>


    (...省略...)


    <appSettings>

        <add key = "AccountName" value="devstoreaccount1"/>
        <add key = "AccountSharedKey" value="Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="/>

        <!-- Change this to point to the base URIs of the storage services against which this sample is run -->
        <!-- When using production-style URIs within this sample, make sure that the HTTP  endpoints do not contain 
         the account name, as the library code adds the account name internally and there is another configuration
         setting for the account name. An example of a valid production-style URI for this sample's 
         configuration file is:
            <add key="StorageEndpoint" value="http://blob.baseuri.com/"/>
         Note that it is NOT http://***accountname***.blob.baseuri.com/. 
    -->

        <add key="BlobStorageEndpoint" value="http://127.0.0.1:10000"/>

        <add key="QueueStorageEndpoint" value="http://127.0.0.1:10001"/>

        <add key="TableStorageEndpoint" value="http://127.0.0.1:10002"/>

        <!-- For production servers, set this to false, otherwise to true.
         For example, it must be true for and endpoint such as http://127.0.0.1:10000 and false
         for and endpoint such as http://blob.baseuri.com.
         The implementation of the storage client library
         derives this setting automatically.
         Please set this value only if you are sure the derived value is wrong. 
    -->
        <!--<add key="UsePathStyleUris" value="true" />-->


        <!-- Change this if you want to write to a different container to avoid clashing with others using this
    sample against the same instance of the storage service -->
        <add key="ContainerName" value="storagesamplecontainer"/>

    </appSettings>


    (...省略...)


    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="SlipReport_WebRole.SlipReportServiceBehavior">
                    <serviceMetadata httpGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <services>
            <service behaviorConfiguration="SlipReport_WebRole.SlipReportServiceBehavior"
             name="SlipReport_WebRole.SlipReportService">
                <endpoint address="" binding="basicHttpBinding" bindingConfiguration=""
                 contract="SlipReport_WebRole.ISlipReportService">
                    <identity>
                        <dns value="localhost" />
                    </identity>
                </endpoint>
                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
            </service>
        </services>
    </system.serviceModel>
</configuration>

appSettings にアカウントの情報や WASS の各ストレージのエンドポイントを記述しています。これは StorageClient のテストプロジェクト内にある App.config の記述をコピーしました。Development Storage で開発する場合、アカウントやエンドポイントは固定です。

長くなったので今回はここまで

今回は WebRole プロジェクトに WCF サービスをホストさせるところまで行いました。次回は仕上げ。Silverlight から WCF サービスにアクセスしてみます。