Windows Azure Tips from Prospex

システム開発 × インフラ構築・運用 × グラフィックデザイン = プロスペックス

合体

clock June 16, 2011 22:29 by author Ito

前々回、Azureで郵便番号検索サービス(失敗)。
前回、RESTでGETなサービスをただのWCFで作る(成功)。

今回はついに 「RESTでGETなAzure版郵便番号検索サービス」 を作る!
(前々回に目指したけど失敗したわけだが…)

ということで…

 

まずはAzureのプロジェクトを作ります。
Webロールは 「WCF サービス Webロール」 を使用します。

そして、勝手に作られた Service1 とかはいらない子なので消して。

「AJAX 対応 WCF サービス」 を追加。

まずは前回作ったコードをそのままコピーして実行…

 

おうけい。最大の難関を突破した!

 

次に、前々回で作った郵便番号検索部分のコードを移植して実行…

やったよ!かあさん!!

 

さて、次のネタ考えないと…

 

以下が最終的なコードです。

 

[ZipCodeSvc]
namespace AzureWcfService {

    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class ZipCodeSvc {
        
        [OperationContract]
        [WebGet(ResponseFormat=WebMessageFormat.Json , UriTemplate="GetAddress/{zipCode}")]
        public string GetAddress(string zipCode) {
            
            CloudStorageAccount   storageAccount = null;
            CloudTableClient      tableClient    = null;
            ZipCodeServiceContext context        = null;

            string address = string.Empty;

            try {
                storageAccount = AzureStorageAccount.GetStorageAccount();

                tableClient = storageAccount.CreateCloudTableClient();
                tableClient.CreateTableIfNotExist("ZipCode");

                context = new ZipCodeServiceContext(storageAccount.TableEndpoint.ToString(), storageAccount.Credentials);

                var query = context.CreateQuery("ZipCode").Where(r => r.Field1 == zipCode).ToArray();

                address = query.First().Field2 + query.First().Field3 + query.First().Field4;

            } catch {
                address = "取得できません";
            }

            return address;
        }
        
    }
}

 

[AzureStorageAccount]
namespace AzureWcfService {

    public class AzureStorageAccount {

        public static CloudStorageAccount GetStorageAccount() {
            
            try {
                CloudStorageAccount.SetConfigurationSettingPublisher(
                    (configName, configSetter) => {
                        configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
                        RoleEnvironment.Changed += (sender, arg) => {
                            if (arg.Changes.OfType().Any((change) => (change.ConfigurationSettingName == configName))) {
                                if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName))) {
                                    RoleEnvironment.RequestRecycle();
                                }
                            }
                        };
                    }
                );

                return CloudStorageAccount.FromConfigurationSetting("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString");

            } catch {
                return null;

            }
        }
    }

}

 

[ZipCodeEntity]
namespace AzureWcfService {

    public class ZipCodeEntity : TableServiceEntity {

        public ZipCodeEntity() {
            PartitionKey = "";
            RowKey       = "-1";
        }

        public string Field1 { get; set; }
        public string Field2 { get; set; }
        public string Field3 { get; set; }
        public string Field4 { get; set; }

    }

}

 

[Web.config]
<system.serviceModel>
<services>
  <service name="AzureWcfService.ZipCodeSvc">
    <endpoint address="" behaviorConfiguration="AzureWcfService.ZipCodeSvcAspNetAjaxBehavior"
binding="webHttpBinding" contract="AzureWcfService.ZipCodeSvc" /> </service> </services> <behaviors> <endpointBehaviors> <behavior name="AzureWcfService.ZipCodeSvcAspNetAjaxBehavior"> <!--<enableWebScript />--> <webHttp /> </behavior> </endpointBehaviors> <serviceBehaviors> <behavior name=""> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> </behaviors> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> </system.serviceModel>
 


WCFでRESTなサービス作ってみた (Azure無視)

clock May 19, 2011 19:13 by author Ito

いままで、AzureでWCFな郵便番号検索サービスつくるぜ!と、ちまちま作ってきましたが、
今回はAzure無視で行きます!

理由?
今まで散々失敗してきたから…

まずは…普通のWCFサービス作ろう!

…かなり退化しているがキニシナイ。

 

■WCFプロジェクトの作成

VisualStudio(2010)で、「WCF サービス アプリケーション」プロジェクトを作ります。

そして、デフォルトで作られる Service1.svc たちは速攻で亡き者にします。

 

■AJAX 対応 WCF サービス作成 (GET)

前回、普通のWCFサービスを試したため、
今回はちょっと先に進むべく、『AJAX 対応 WCF サービス』 なんてものを使ってみます。
しかも、GETで取得できるものを…

サービスの内容はこんな感じにコーディング

[WcfTestService.svc]

namespace WcfTestService {

    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class WcfTestService {

        [OperationContract]
        [WebGet(ResponseFormat=WebMessageFormat.Json)]
        public string HelloWorld(string name) {
            return "こんにちは、" + name + "さん。";
        }

    }
}

WebGet(ResponseFormat=WebMessageFormat.Json) とすることで、GETで取得できるようだ(JSON形式)。

 

そしておもむろに実行

なんか出た。

「WCF テスト クライアント」 には別に用はないため、閉じ。

ブラウザ (Chrom) を開いて…
URLは、
http://localhost:49652/WcfTestService.svc/HelloWorld?name=YAMADA と入力…

 

 

幸先よさそうだ。

 

■[?name=YAMADA] がかっこ悪い

クエリ文字列は今ではかっこ悪い?ので、[HelloWorld/YAMADA] で呼べるようにしてみる。

プログラムを変更してみる

[WcfTestService.svc WcfTestService.HelloWorld メソッド]

[OperationContract]
[WebGet(ResponseFormat=WebMessageFormat.Json, UriTemplate="HelloWorld/{name}")]
public string HelloWorld(string name) {
    return "こんにちは、" + name + "さん。";
}

そして実行→ブラウザでアクセス (
http://localhost:49652/WcfTestService.svc/HelloWorld/YAMADA)

 

 

シボンヌ。

エラーメッセージ的に、エンドポイントの設定を変えてあげればいいようだ。
ということで、いろいろと調べてみて、Web.config を編集してみた。

[Web.config]

<behavior name="WcfTestService.WcfTestServiceAspNetAjaxBehavior">
  <!-- UriTemplate を使用する場合、<enableWebScript/>ではなく、<webHttp/>に変更するみたい -->
  <!-- 削除 -->
  <!-- <enableWebScript /> -->
  <!-- 追加 -->
  <webHttp />
</behavior>

そして実行…

 

 

やばい…調子よすぎる…

 

■[.svc] がかっこ悪いです。

URLに 「~.svc/~」 の .svc が非常にかっこ悪いし気持ち悪い。

これを何とかするために試行錯誤…

 

・Web.config の endpoint をいじってみる

<endpoint address="" をいじってみたが、どうやってもできなかった…

 

・サービスを起動するプログラムを作る

エンドポイントを指定して起動させるといいみたい…メンドクサイ…
なので、試しませんでした。

 

・MVCなどのルーティングを使用してみる

Global.asax で、RouteTable なんたらかんたらと記述すると、できるようだ。
(最近ASPで使ってみた)

内容はこんな感じ。

[Global.asax]

protected void Application_Start(object sender, EventArgs e) {

    RouteTable.Routes.Add(
        new ServiceRoute("WcfTestService", new WebServiceHostFactory(), typeof(WcfTestService)));

}

 

そして起動…(http://localhost:49652/WcfTestService/HelloWorld/YAMADA)

 

 

これ超楽や…

 

今回はAzureに全く関係なかったけど、まあ結果でたからOK。



WCFわけわかんねぇ

clock April 28, 2011 21:33 by author Ito

こんばんは。

前回の続きで、今回は「WCFにjQueryでRESTな方法で住所を取得しよう」に挑戦…

 

できませんでした。

 

まずWCFがよくわからない。

とりあえずごく簡単なWCFサービスを作成はできた。
(サーバー側でWCF通信はできた)

内容はこんなの。

 

■WCFサービス

<IZipCodeSvc.cs>

[ServiceContract]
public interface IZipCodeSvc {

    [OperationContract]
    string GetAddress(string zipCode);
}

<ZipCodeSvc.svc.cs>

public class ZipCodeSvc : IZipCodeSvc {
        
    /// <summary>
    /// 郵便番号から住所を取得する
    /// </summary>
    /// <param name="zipCode"></param>
    /// <returns></returns>
    public string GetAddress(string zipCode) {

        CloudStorageAccount   storageAccount = null;
        CloudTableClient      tableClient    = null;
        ZipCodeServiceContext context        = null;

        string address = string.Empty;

        try {
            storageAccount = WCFServiceTest.AzureStorageAccount.GetStorageAccount();

            tableClient = storageAccount.CreateCloudTableClient();
            tableClient.CreateTableIfNotExist("ZipCode");

            context = new ZipCodeServiceContext(storageAccount.TableEndpoint.ToString(), storageAccount.Credentials);

            var query = context.CreateQuery<ZipCodeEndity>("ZipCode").Where(r => r.Field1 == zipCode).ToArray();

            address = query.First().Field2 + query.First().Field3 + query.First().Field4;

        } catch {
            address = "取得できません";
        }

        return address;
    }
}

<WCFServiceTest.AzureStorageAccount>

public class AzureStorageAccount {

    public static CloudStorageAccount GetStorageAccount() {
            
        try {
            CloudStorageAccount.SetConfigurationSettingPublisher(
                (configName, configSetter) => {
                    configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
                    RoleEnvironment.Changed += (sender, arg) => {
                        if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>().Any((change) => (change.ConfigurationSettingName == configName))) {
                            if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName))) {
                                RoleEnvironment.RequestRecycle();
                            }
                        }
                    };
                }
            );

            return CloudStorageAccount.FromConfigurationSetting("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString");

        } catch {
            return null;

        }
    }
}

 

■Web側 (MVC)

<Controller>

public class ZipCodeController : Controller {

    //
    // GET/POST: /ZipCode/
    public ActionResult Index(string zipCode) {

        // サービスクライアント作成 (まずはローカル)
        WCFTestService.ZipCodeSvcClient svc
                = new WCFTestService.ZipCodeSvcClient(new BasicHttpBinding(),
                                                          new EndpointAddress("
http://127.0.0.1:81/ZipCodeSvc.svc"));

        // 住所を取得
        string address = svc.GetAddress(zipCode);

        ViewData["Title"] = Request.HttpMethod;
        ViewData["ZipCode"] = zipCode;
        ViewData["Address"] = address;

        return View();
    }
}

<View>

    <h2><%: ViewData["Title"] %></h2>
    <p>
        〒<%: ViewData["ZipCode"] %><br />
        <%: ViewData["Address"] %><br />
    </p>
    <% using ( Html.BeginForm() ) { %>
        <%: Html.TextBox("ZipCode") %>
        <input type="submit" value="検索" />
    <% } %>

 

そして実行…   

ただのWCFできた。

次、AJAX対応のWCFサービス作ろう…
というところで詰まった。

 

明日からの連休で、いろいろ試して、次回はちゃんとしたものを書けるようにします…

 



サービス作ってみたくなったんです

clock March 17, 2011 09:09 by author Ito

今回は、AzureでWebサービス作ってみよう。

 

ということで、まずはasmxファイルで作ってみる。

適当なWebロールにasmxファイルを追加して、以下を記述。

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
[ScriptService]  // スクリプトから呼び出す為の属性
public class WebService1 : System.Web.Services.WebService {

    [WebMethod]
    public string HelloWorld() {
        return "Hello World";
    }

    [WebMethod]
    [ScriptMethod(ResponseFormat=ResponseFormat.Json)]  // Json形式で返す
     public DateTime NowDate() {
        return DateTime.Now;
    }
}

 

勝手に作られるHelloWorldと、ただ現在時刻をJSON形式で返すだけのサービス・・・

 

これを呼び出す側を作ってみる。(MVCで作った)

[HandleError]
public class HomeController : Controller {

    public ActionResult Index() {

        WebService1 service = new WebService1();

        ViewData["Message"] = service.HelloWorld();

        return View();
    }

}

 

勝手に作られるコードに毛が生えた!

 

そして実行・・・

 

よしできた。終了。

 

・・・

 

あまりにも内容が薄いので、もう少し毛を生やします・・・

 

WebサービスからjQueryのAjaxで現在時刻を取得・表示してみる。

先ほど作った呼び出し側のページ(MVCビュー)に時刻を表示する部分を追加。

<p>現在の時刻:<span id="now_date"></span></p>

 

そして、Ajax取得するためのスクリプト追加。

<script type="text/javascript">

    $(document).ready(function() {
        setInterval(function() {
            $.ajax({
                url: "WebService1.asmx/NowDate",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                type: "POST",
                success: AjaxSuccess
            });
        }, 1000);
    });

    function AjaxSuccess(data, dataType) {
        $("#now_date").text(ConvertMSJsonDate(data).toString());
    }

    // ASP.net WebサービスからJSONで返されたDateTime型を
    // javascriptのDate型に変換
    function ConvertMSJsonDate(jsonDate) {
        jsonDate.d.match(/\/Date\((.*?)\)\//g);
        return new Date(parseInt(RegExp.$1));
    }

</script>

 

実行・・・

できた!

 

豆知識

jQueryで asmx Webサービス

jQuery.ajaxのurlパラメータに、asmxファイルのUrlを指定し、
/の後に、サービスのメソッド名を記述するようだ。
サービスに渡す引数は、dateパラメータで指定する。

DateTimeの罠

ASP.netのWebサービスからDateTime型をJSONで取得すると、
  { "d": "/Date(1300323898991)/"}
というオブジェクトが返ります。

こいつをjavascriptのDate型に変換するには、"/Date(1300323898991)/"の数値を切り出し、
Date型のコンストラクタに指定してあげないといけないみたい。

 

あれ?今回の内容、Azure関係ないような気がする・・・



サーバー監視の第一歩

clock March 3, 2011 21:37 by author Ito

 さて、今回はふと思った事 「azureのリソース状況(CPU使用率とか)でも取得してみようかな」 でもやってみよう。

まずは各種リソースの取得方法を調べてみる。
…… PerformanceCounter 使えばいいみたい。

で、次はおもむろに WorkerRole を作成し、Runメソッドに直で書いてみる。

public override void Run() {

    while ( true ) {
        PerformanceCounter processorTimeCounter  = new PerformanceCounter("Processor", "% Processor Time", "_Total", ".");
        PerformanceCounter availableBytesCounter = new PerformanceCounter("Memory", "Available Bytes");
        PerformanceCounter committedBytesCounter = new PerformanceCounter("Memory", "Committed Bytes");

        Trace.WriteLine("CPU : " + processorTimeCounter.NextValue() + "%");
        Trace.WriteLine("Available MBytes : " + availableBytesCounter.NextValue() / 1024.0 / 1024.0 + "MBytes");
        Trace.WriteLine("Committed Bytes  : " + committedBytesCounter.NextValue() / 1024.0 / 1024.0 + "MBytes");

        Thread.Sleep(1000);
    }
}

そして実行 (デバッグ)

CPU : 0%
Available MBytes : 780.40234375MBytes
Committed Bytes  : 4535.29296875MBytes
CPU : 0%
Available MBytes : 783.65625MBytes
Committed Bytes  : 4531.33984375MBytes

"CPU : 0%" ってなんですか?

 

Azureだからだめなのかと思い、普通のコンソールプロジェクトでやってみたが同じ結果…

仕方ないので毎度のGoogle先生に伺ってみたが、なかなか返事が返ってこない…

そしてついに見つけた

カウンタの計算される値が 2 回のカウンタ読み取りに依存する場合、最初の読み取りでは 0.0 が返されます。
          http://msdn.microsoft.com/ja-jp/library/system.diagnostics.performancecounter.nextvalue%28v=VS.80%29.aspx
                                                       MSDN : PerformanceCounter.NextValue メソッド より

CPU使用率は上記に該当する模様。

 

な、なんだってー!

 

ということで、プログラム書きなおしてみた。

public override void Run() {

    // ループの外に出しただけ
    PerformanceCounter processorTimeCounter  = new PerformanceCounter("Processor", "% Processor Time", "_Total", ".");
    PerformanceCounter availableBytesCounter = new PerformanceCounter("Memory", "Available Bytes");
    PerformanceCounter committedBytesCounter = new PerformanceCounter("Memory", "Committed Bytes");

    while ( true ) {
        Trace.WriteLine("CPU : " + processorTimeCounter.NextValue() + "%");
        Trace.WriteLine("Available MBytes : " + availableBytesCounter.NextValue() / 1024.0 / 1024.0 + "MBytes");
        Trace.WriteLine("Committed Bytes  : " + committedBytesCounter.NextValue() / 1024.0 / 1024.0 + "MBytes");

        Thread.Sleep(1000);
    }
}

実行

CPU : 10.32648%
Available MBytes : 830.2109375MBytes
Committed Bytes  : 4754.65234375MBytes
CPU : 14.0092%
Available MBytes : 832.2734375MBytes
Committed Bytes  : 4751.90234375MBytes

…………OK、できた。

あとはこれらデータをストレージテーブルにでも格納すればOK。

 

 

これって、このWorkerRoleだけのリソース情報だよな…
フロント部のWebRoleの情報が知りたいんだが…

つかえねぇ…



AzureをPowerShellで管理

clock February 28, 2011 22:58 by author Tanaka

本日はAzureでPowerShellをつかってみる。
以下のネタは実用性があまりないですが・・・

■Windows 7ならデフォルトでPowerShellを標準搭載しているから、
以下のURLからCmdLetsをダウンロードしてインストールする 

http://archive.msdn.microsoft.com/azurecmdlets

■Management CmdLetsでAzureの管理をするには 
以下の情報が必要  

1.サービス名 → http://azurecmdlettest.cloudapp.net/というプロダクションがあったらazurecmdlettestの部分 
2.サブスクリプションID → Azureの管理画面から確認できる 
3.アカウント証明書 → ローカル、Azure上に配置する必要がある。  

※アカウント証明書を作成して配置する方法
(以下の参考URLではコマンドラインツールを使用して、あらかじめアップロードが可能な状態の証明書の作成方法が書いてある。)
http://www.atmarkit.co.jp/fdotnet/special/azuresdk13_02/azuresdk13_02_01.html

■実用性はあまりないが、プロダクション環境からサービスを削除してみる。 

ProductionRemove.ps1というファイル名にしてみた。

以下内容
$name = "azurecmdlettest"
$sub = "<サブスクリプションID>"  
$cert = Get-Item cert:\CurrentUser\My\"<証明書の拇印>"  

Add-PSSnapin AzureManagementToolsSnapIn  
Get-HostedService -ServiceName $name -certificate $cert -SubscriptionID $sub |  
Remove-Deployment -Slot Production |  
Get-OperationStatus -WaitToComplete  

※証明書の拇印は以下のコマンドで確認できる。  
PS C:\> Get-Item cert:\CurrentUser\My\*  

azurecmdlettestは確かに削除できた。



ケチるための小ネタ

clock February 24, 2011 21:46 by author Ito

今までただ理論を考えるだけでテストプログラムも書いてこなかったけど、今回はちゃんとプログラム書いてみた。
今までのネタ関係ないけどね・・・

クラウドになって気になることといえば、「料金」が気になるなぁっと思い、
その料金を少しでもケチる方法を考えた。

それは、

とにかくデータ圧縮してしまえ!

以上。

 

これだけじゃアレなので…

.NET Framework には、データ圧縮をしてくれるクラス
「System.IO.Compress.GZipStream」 と 「System.IO.Compress.DeflateStream」 が用意されています。

前者が、Zip形式の圧縮を行ってくれるクラス、後者がDeflateアルゴリズムで圧縮を行うクラスです。
Zipも圧縮アルゴリズムにDeflateアルゴリズムを使用しているので、実質差はほとんどありません。(GZipStreamだとgzipのヘッダをつけてくれるみたい)

このクラスを使えば、blobストレージに圧縮したデータを格納して、少しでもケチることができるということです。

至極 簡単にプログラム書いてみると・・・


CloudBlobContainer  blobContainer;
HttpPostedFileBase  postedFile;

~略~

// 圧縮処理 ----

// GZip圧縮ストリーム準備
MemoryStream memoryStream = new MemoryStream();
GZipStream     zipStream        = new GZipStream(memoryStream, CompressionMode.Compress, true);
            
// デフレート圧縮 (UploadFile → MemoryStream)
postedFile.InputStream.CopyTo(zipStream);
zipStream.Close();

// blobに圧縮したファイルを保存
CloudBlob blob = blobContainer.GetBlobReference("test_blob");
blob.UploadByteArray(memoryStream.ToArray());

// 確認
blob.DownloadToFile("c:\\temp\\blob.dat");

// 展開処理 ----

// blobからデータ取得
CloudBlob        blob          = blobContainer.GetBlobReference("test_blob");
MemoryStream blobStream = new MemoryStream(blob.DownloadByteArray());

// データ展開
GZipStream     zipStream  = new GZipStream(blobStream, CompressionMode.Decompress);
MemoryStream outStream = new MemoryStream();
zipStream.CopyTo(outStream);

// 確認
System.IO.File.WriteAllBytes("c:\\temp\\decompress.dat", outStream.ToArray());

このネタ実用性あるのか・・・



Visual Studio 変換ウィザードへようこそ

clock February 8, 2011 23:09 by author fujii

歓迎されるのは気持ちがいいものだが、

「Visual Studio 変換ウィザードへようこそ」って言われても……More...



俺のAzure

clock January 19, 2011 22:57 by author fujii

漢なら、自腹でデプロイだ!

「Windows Azure Platform」のサブスクリプション申し込みをしてみた。More...



仕事納め

clock December 30, 2010 12:18 by author Sekine

お疲れ様!!

本日、今年最後の営業日です。

 

今年の景気は!?どうだったのか

良くなると言われてきていますが

各個に目を向けて、それが実感できる人はどの位実感できたでしょうか

政権交代もあり、エコポイントや子ども手当など新しい制度も出来、

また、時勢的に野菜の高騰など、私生活に直撃する物事もあり

 

良い年になったかな?っと自問自答して

来年はどうしたいのか、良く考えてみたいと思います。

 

年納めといえば、

今日は東証で大納会の日です。

今はお昼なので、前場終了の日経平均は・・・

 

10205円 81銭

1万超えてるので良いか。(そうなのか?

 

大納会の会場では、

はやぶさ の5分の1スケールの模型が展示されるようです。

正直、見たいです

はやぶさと言えば、今年注目されたキーワード。

音信不通でさまよった挙句、長い帰路を生還?した功労者・機ですね

「おかえりー! はやぶさ」 という映像が、良くメディアで流れていましたが

感動しましたね。

 

先日JAXAi(東京千代田区)が事業仕分けにより閉館になってしまいました。

宇宙服に見立てた顔写真は・・

つくばのJAXAに行けば写真撮れますよ。

 

 

..Azureとは関係なかったね

 

お疲れ様でした。

:関根

 



Sign In