normalian blog

Let's talk about Microsoft Azure, ASP.NET and Java!

2014年3月, 4月の JAZUG のイベント

Japan Windows Azure User Group が 2014年3月、4月に実施するイベントをまとめてみた。都合が合いそうな方(合わなくとも是非調整して)は是非参加してほしい!

3/29(土) Global Windows Azure Boot Camp 2014 in Japan!! at 品川

Global Windows Azure Bootcamp 2014 in Japan!! は、全世界で同一日に Windows Azure イベントの日本枠になる。Global Windows Azure Bootcamp を主催するスウェーデンからの Magnus氏 が来日する他、ブルガリアの Mihail 氏とも協力してブルガリアの Global Windows Azure Bootcamp とも内容を連携しあう。世界的なイベントになる!

4/12(土) JAZUG女子部 第6回勉強会 ~日本DCがやって来たヤァ!ヤァ!ヤァ! at 品川

Japan Windows Azure User Group 女子部 第6回勉強会が 4/12 に開催されます。 JAZUG女子部 第6回勉強会 ~日本DCがやって来たヤァ!ヤァ!ヤァ! から参加登録可能であり、Windows Azure の日本データセンタって何が美味しいの?、MS本社で新機能が多々発表される Build 2014 参加者の内容連携だったりと、内容盛りだくさんだ。

4/26(土) 第3回JAZUG静岡勉強会 at 浜松

JAZUG の静岡支部、第三回目の勉強会になる。第3回JAZUG静岡勉強会から参加登録可能だ。主催・運営メンバーはJAZUGのコアメンバなので運営クオリティは期待できるのはもちろんなので、内容は普段都内に出てくるのが難しい方は是非参加してほしい。
また、静岡の美味しい食べ物に興味のある方も参加してみても良いかも?

Windows Azure の Webサイトで Tomcat, Jetty の稼働をサポート!!!

さて、今回はWindows Azure アドベントカレンダー の15日目だが、ここで大きなニュースがある。
来た! Web サイトで Java が動く日がついに来たのだ! さあ皆、↓の画面を見るんだ!!
f:id:waritohutsu:20140315204517j:plain

上記の様に JDK 1.7 update 51 が選択可能で、ついでに Tomcat と Jetty が動くのが確認できる。今回はこのネタを話したいと思う。

Kudu を利用したフォルダ構成、環境変数の確認

次にちょっとフォルダ構成を確認するために、Kudu を利用したいと思う。Kudu を知らない人は、No.1 が詳しい記載のある Windows Azure Web Sitesの魅力を120%引き出す を確認してみよう!

一旦は Tomcat 側で設定した Web サイトを作成し、Web サイトに https://<サイト名>.scm.azurewebsites.net/ でアクセスして、構造を確認してみよう。Kudu の Debug Console を利用するこでフォルダ構成をチェックできる。Tomcat のインストールディレクトリを確認したところ、以下の様に D:\Program Files (x86)\ 以下に配置されている。

D:\Program Files (x86)\apache-tomcat-7.0.50>dir
Volume in drive D is Windows
Volume Serial Number is 6416-721C
Directory of D:\Program Files (x86)\apache-tomcat-7.0.50
03/11/2014 10:20 PM <DIR> .
03/11/2014 10:20 PM <DIR> ..
03/11/2014 10:20 PM <DIR> bin
03/11/2014 10:20 PM <DIR> conf
03/11/2014 10:20 PM <DIR> lib
03/11/2014 10:20 PM <DIR> logs
03/11/2014 10:20 PM <DIR> temp
03/11/2014 10:20 PM <DIR> webapps
03/11/2014 10:20 PM <DIR> work
03/11/2014 10:20 PM 57,862 LICENSE
03/11/2014 10:20 PM 1,228 NOTICE
03/11/2014 10:20 PM 9,258 RELEASE-NOTES
03/11/2014 10:20 PM 16,742 RUNNING.txt
4 File(s) 85,090 bytes
9 Dir(s) 9,324,318,720 bytes free

次に、war を配置する webapps の設定を確認するために conf/server.xml の中身の一部も確認してみる。

D:\Program Files (x86)\apache-tomcat-7.0.50\conf>cat server.xml 

<中略>

<Host name="localhost" appBase="d:\home\site\wwwroot\webapps" xmlBase="d:\home\site\wwwroot\"
unpackWARs="true" autoDeploy="true" workDir="${site.tempdir}">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="${site.logdir}"
prefix="site_access_log." suffix=".txt"
pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host> 

以下の様に war を配置するフォルダは appBase="d:\home\site\wwwroot\webapps" で記載されている。どうやらここに war を配置すればよいのだと推察できる。次に d:\home\site\wwwroot\webapps を確認すると、ROOT フォルダが存在し、以下に一つだけ index.jsp ファイルが存在している。
f:id:waritohutsu:20140315204906j:plain

ここで http://<サイト名>.azurewebsites.net にアクセスすると以下の画面が表示され、Oracle JDK かつ GMT タイムゾーンであることが確認できる。
f:id:waritohutsu:20140315204947j:plain

次に、環境変数を確認する。ここでは JDK, Jetty, Tomcat 向けに設定された環境変数の情報が確認可能だ。
f:id:waritohutsu:20140315205001j:plain

自前アプリをデプロイ

Kudu さんの Debug Console からドラッグアンドドロップで HelloWorld.war を d:\home\site\wwwroot\webapps 以下に配置した後、https://<サイト名>.azurewebsites.net/HelloWorld にアクセスすると以下の様に自前で作成した HelloWorld.war が正しくデプロイしていることが確認できる。
f:id:waritohutsu:20140315205519j:plain

次に git clone を利用して Web サイトをクローンしたところ、d:\home\site\ から引っこ抜かれてしまったので、毎度 war を push する必要がありそうだ。この辺りは Eclipse からのデプロイ等の改善が期待されるところだ。

C:\xxxxxxxxxxxxx\ilovejava>dir /a
 ドライブ C のボリューム ラベルがありません。
 ボリューム シリアル番号は D461-5218 です

 C:\xxxxxxxxxxxxx\ilovejava のディレクトリ

2014/03/15  15:15    <DIR>          .
2014/03/15  15:15    <DIR>          ..
2014/03/15  19:28    <DIR>          .git
2014/03/15  15:15            65,954 hostingstart.html
2014/03/15  20:51    <DIR>          webapps

仮想ネットワーク上に作成する仮想マシンに対し、固定 IP アドレスを割り当て可能に

今まで仮想ネットワーク上に作成する仮想マシンIPアドレスは固定化できず、DHCPで割り振られる IP アドレスのみ利用可能でしたが、 PowerShell cmdlets for Windows Azure version 0.7.3 から IP アドレスが固定化できるようになった。
Windows Azure now allows to set fixed IP-addresses for virtual machines

PowerShell のコマンドから以下をたたくと、IPアドレス固定化に利用するためのコマンド(Set-AzureStaticVNetIP)が存在しているのが確認できる。

PS C:\> Get-Command *Azure*

f:id:waritohutsu:20140306005036j:plain

備考

DHCP で動的に割り当てられる IP は「10.x.x.4 ~ の 4から割り当てられる」や DNSサーバーの割り当ては固定化できる等の特性を考慮した工夫である程度対応できたが、PowerShell cmdlets for Windows Azure version 0.7.3 からは、仮想マシンに対して明示的に固定のIPアドレスをふれるようになった。
Set-AzureStaticVNetIP が利用できるようになる前の情報については、神ブログである SE の雑記 に記載されている AzureVM の DNS の設定についての注意点を参照のこと

Web サイトのバックアップ/復元 機能を利用してみる

Azure: ExpressRoute Dedicated Networking, Web Site Backup Restore, Mobile Services .NET support, Hadoop 2.2, and more にて発表された Webサイトのバックアップ/復元機能が便利そうだったのでちょっと触ってた。

まず簡単なWEBアプリを作る

Node.js で簡単にテーブル操作する処理を以下の様に実装した。今回は Node.js アプリ& git デプロイした場合のフォルダ構成となる点だけ認識頂ければ幸いだ。

  • server.js
var http = require('http')
var port = process.env.PORT || 1337;

var azure = require('azure');
var ServiceClient = azure.ServiceClient;
var TableQuery = azure.TableQuery;
var tableClient = azure.createTableService("<ストレージアカウント名>",
 "<ストレージアカウントキー>",
 "http://<ストレージアカウント名>.table.core.windows.net/");

var tableName = 'posts';
var partition = 'part1';
var rowkey = 'bbbbbb';

http.createServer(function(req, res) {
  tableClient.createTableIfNotExists(tableName, function (err, created) {
      var now = new Date().toGMTString();
      var entity = {
          PartitionKey: partition,
          RowKey: rowkey + now,
          title: 'Post one',
          body: 'Body one at WebSite',
          created_at: now };
      tableClient.insertEntity(tableName, entity, null, function(err){
         console.log(err);
      });
  });

  res.writeHead(200, { 'Content-Type': 'text/html; charset=UTF-8' });
  res.end('無事にテーブルストレージにインサートした模様\n');
}).listen(port);

以下のコマンドでモジュールをインストール後、git push してアプリケーションを動作させる。

npm install azure 
git add .
git commit -m "commit"
git push <hogehoge>

バックアップを試す

Webサイトの管理画面から「バックアップ プレビュー」のタブがあるので選択する。「標準モード」でしか利用できないので、注意が必要だ。
f:id:waritohutsu:20140304011118j:plain

自動化されたバックアップを頻度を含め設定できるほか、何処のストレージサービスに格納するかを設定できる。
f:id:waritohutsu:20140304011144j:plain

「今すぐバックアップ」を選択すると選択したストレージサービスにデータが格納される。ストレージサービスに「websitebackups」フォルダが作成され、「_<日付>」フォーマットの xml ファイルと zip ファイルが格納されている。
f:id:waritohutsu:20140304011207j:plain

  • normalianbkup_201403031549.xml
<?xml version="1.0" encoding="utf-8"?>
<BackupDescription xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/windowsazure">
  <Version>0</Version>
  <Name><Webサイト名>_<日付></Name>
  <HostNames xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <d2p1:string><Webサイト名>.azurewebsites.net</d2p1:string>
  </HostNames>
  <Databases />
</BackupDescription>
  • normalianbkup_201403031549.zip ファイルの中身
normalianbkup_201403031549.zip
└─fscontent
   ├─LogFiles
   │  └─Git
   │      └─trace
   └─site
       ├─deployments
       │  ├─9e3f836b7daa0648bb95a9371f3fd748d
       │  └─tools
       ├─repository
       │  └─.git
       └─wwwroot
           └─node_modules

zip ファイル側は site 以下のファイルがまるっと zip に固められていることがわかる。

復元を試す

「今すぐ復元」を選ぶとどのバックアップファイルからWebサイトを復元するか選択可能だ。
f:id:waritohutsu:20140304011637j:plain

また、復元先はもともとのWebサイトはもちろん、新たなWebサイトを作成してバックアップすることも可能だ。
f:id:waritohutsu:20140304011648j:plain

Open JDK ベースの JVM Zulu が Web Platform Installer でインストール可能に!

ご存じでない方もいると思うが、OpenJDK ベースである Azul Zulu が Web Platform でインストール可能になった。Zulu は Windows Azure Plugin for Eclipse with Java にも統合されており、Windows Azure 上で Java を動作させる際に重要な役割を果たしている。

Web Platform Installer を利用してインストール

Web Platform Installer を起動し、検索までから Java と検索することで以下の画面が表示される。
f:id:waritohutsu:20140209143119p:plain

そのまま[追加]ボタンを押下すると以下の様にインストールされる。

  • C:\Azul\zulu1.7.0_45-7.2.0.3-win64 以下に JDK がインストールされる(※注 バージョンによって適宜読み替えること
  • 環境変数 JAVA_HOME が以下に設定される(※注 既存の JDK をインストールしている場合は注意)
C:\Users\normalian>echo %JAVA_HOME%
C:\Azul\zulu1.7.0_45-7.2.0.3-win64

Web Platform Installer を利用することで、常に最新のバージョンの Zulu を利用することが可能だ。

余談

Windows Azure Plugin for Eclipse with Java をインストールしている場合、生成される Windows Azure 向けのプロジェクトテンプレートに含まれる package.xml にも zulu を取得する URL が含まれている。以下に抜粋したものを記載する。

  • package.xml の抜粋
        <!-- Create a sample role -->
        <workerrole approotdir="${basedir}\WorkerRole1\approot" name="WorkerRole1">
          <startupenv cloudvalue="%DEPLOYROOT%\zulu1.7.0_40-7.1.0.0-win64" name="JAVA_HOME" type="jdk.home" value="%DEPLOYROOT%\zulu1.7.0_40-7.1.0.0-win64"/>
          <startupenv name="PATH" type="jdk.path" value="%JAVA_HOME%\bin;%PATH%"/>
          <startupenv name="CATALINA_HOME" type="server.home" value="%DEPLOYROOT%\apache-tomcat-7.0.47"/>
          <startupenv name="SERVER_APPS_LOCATION" type="server.app.loc" value="%CATALINA_HOME%\webapps"/>
          <component cloudaltsrc="http://azure.azulsystems.com/zulu/zulu1.7.0_40-7.1.0.0-win64.zip" cloudmethod="unzip" cloudsrc="auto" cloudupload="AUTO" deploydir="%DEPLOYROOT%" deploymethod="copy" importmethod="copy" importsrc="C:\Program Files\Java\jdk1.7.0_40" type="jdk.deploy"/>
          <component cloudmethod="unzip" cloudsrc="auto" cloudupload="AUTO" deploydir="%DEPLOYROOT%" deploymethod="copy" importmethod="copy" importsrc="C:\opt\tomcat\apache-tomcat-7.0.47" type="server.deploy"/>

Windows 向けの Open JDK で公式ビルドは存在しないが、Zulu という選択肢も取れることがわかる。

Knockout MVC を使ってみる

今回は Knockout.js を ASP.NET MVC で活用するためのライブラリである Knockout MVC を利用してみる。同ライブラリを利用することで、ASP.NET MVC でのモデルバインディングが容易になり、ASP.NET 側と JavaScript 側の機能連携が非常に容易になる。

インストール方法

Visual Studio から NuGet の管理コンソールを起動し、検索窓に「knockout」と入力した結果の P.3 辺りに Knockout MVC が発見できる。
f:id:waritohutsu:20140113134146j:plain

次に、Knockout.js を利用するためには ASP.NET MVC プロジェクトに対して以下の修正をする必要がある。

  • App_Start/BundleConfig
public class BundleConfig
{
    // バンドルの詳細については、http://go.microsoft.com/fwlink/?LinkId=301862 を参照してください
    public static void RegisterBundles(BundleCollection bundles)
    {
        bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                    "~/Scripts/jquery-{version}.js"));

        bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                    "~/Scripts/jquery.validate*"));

        bundles.Add(new ScriptBundle("~/bundles/jqueryunobtrusive").Include(
        "~/Scripts/jquery.validate.unobtrusive.js"));

        //knockout.s 用
        bundles.Add(new ScriptBundle("~/bundles/knockout").Include(
        "~/Scripts/knockout-{version}.js"));
        bundles.Add(new ScriptBundle("~/bundles/knockoutmapping").Include(
        "~/Scripts/knockout.mapping-latest.js"));

        // 以下は省略
    }
}
  • Views/Shared/_Layout.cshtml
<!DOCTYPE html>
<html>
<head>
//中略
</head>
<body>
//中略
    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; @DateTime.Now.Year - マイ ASP.NET アプリケーション</p>
        </footer>
    </div>

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @Scripts.Render("~/bundles/knockout")
    @Scripts.Render("~/bundles/knockoutmapping")
    @RenderSection("scripts", required: false)
</body>
</html>

という感じで、Knockout.js を画面側で読みこめるように設定しておく必要がある。

簡単な使い方

以下にサンプルコードを記載してみる。

  • Person.cs Name, Age プロパティはさておき、Summary プロパティに Computed 属性を付与している点に注目していただきたい。Computed 属性を付与することで、JavaScript 側にロジックを自動生成することができる。
using System.ComponentModel.DataAnnotations;
using DelegateDecompiler;

namespace KnockoutMVCSample.Models
{
    public class Person
    {
        [Display(Name = "名前"), Required]
        public string Name { get; set; }
        [Required, Display(Name = "年齢"), Range(typeof(int), "0", "200")]
        public int Age { get; set; }

        [Computed]
        public string Summary
        {
            get
            {
                var ret = Name + "は";
                if (Age < 20)
                {
                    ret += "まだまだ未成熟な果実(/ω\)イヤン";
                }
                else
                {
                    ret += "熟れた果実(*´Д`)ハァハァ";
                }
                return ret;
            }
        }

        // 後述するが、 ToString を上書きすると死ぬ
        //public override string ToString()
        //{
        //    return string.Format("私は {0}、{1}歳☆(ゝω・)vキャピ", this.Name, this.Age);
        //}
    }
}
  • HomeController.cs 通常の ASP.NET MVC のコントローラであり、特に留意する点はない
using System.Web.Mvc;
using KnockoutMVCSample.Models;
using System.Diagnostics;

namespace KnockoutMVCSample.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View(new Person()
            {
                Name = "幼女",
                Age = 9
            });
        }

        [HttpPost]
        public ActionResult Index(Person person)
        {
            Trace.WriteLine(string.Format("私は {0}、{1}歳☆(ゝω・)vキャピ", person.Name, person.Age));
            return View(person);
        }

        //中略
    }
}
  • Home/Index.cshtml 画面最初に Html.CreateKnockoutContext() を利用して Knockout MVC 用のインスタンスを作成しており、フォーム部品を作成する際に同インスタンスを利用している点に注目してほしい
@using PerpetuumSoft.Knockout
@model KnockoutMVCSample.Models.Person

@{
    ViewBag.Title = "Home Page";
    var ko = Html.CreateKnockoutContext();
}

@using (Html.BeginForm())
{
    <br /><br />
    <div>
        <h3>knockout.js でのマッピング</h3>
        @Html.LabelFor(m => m.Name) : @ko.Html.TextBox(m => m.Name, new { value = Model.Name, name = "Name" }) @Html.ValidationMessageFor(m => m.Name)<br />
        @Html.LabelFor(m => m.Age) : @ko.Html.TextBox(m => m.Age, new { value = Model.Age, name = "Age" }) @Html.ValidationMessageFor(m => m.Age)<input id="update_button" type="button" value="年齢+1" /> <br />
        <div>
            名前と年齢についてのサマリ:@ko.Html.Span(m => m.Summary, new { id = "summary" })
        </div>
        <br />        
        <input type="submit" name="submit" value="送付" /><br />
    </div>
}
@section scripts
{
    @ko.Apply(Model)
    <script type="text/javascript">
        $(function() {
            $('#update_button').click(function() {
                $('#Age').text(viewModel.Age(viewModel.Age() + 1));
            });
        });
    </script>
}

更に、「注意点」のスクリーンショットを参照して頂ければわかると思うが、Knockout MVC は viewModel という変数名でモデルを生成するため、上記の記載方法で画面上で JavaScript の viewModel を操作することができる。

注意点

Computed 属性を付与しない場合、以下の様に JavaScript 側の計算用ロジックが自動生成されない。
f:id:waritohutsu:20140113134149j:plain

また、モデルクラス(今回は Person.cs) の ToString() メソッドをオーバーライドすると、以下の様に JavaScript 側の自動生成コードがおかしくなってしまう点にも注意が必要だ。
f:id:waritohutsu:20140113134151j:plain

参考

Knockout MVC は以下の様にサンプルが豊富なため、こちらも参照頂きたい。

Windows Azure SDK for .NET の Management Library を利用して Webサイト の構成を変更する

前回の記事である Windows Azure SDK for .NET の Management Library を利用して Webサイト を動的に作成してみる で疎通までの簡単な手順とWebサイトの作成までを紹介したが、今回は Web サイトの設定情報を更新する方法を紹介する。

サンプルコードを実行する

ダラダラと文章を書いても仕方ないので、以下に試したコードと実行結果を記載する。作成済みの Web サイトの情報を取得する際に、GetAync() メソッドと GetConfigurationAsync() メソッドで取得できる情報が異なる点に注意が必要だ*1

  • サンプルコード
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Management;
using Microsoft.WindowsAzure.Management.WebSites.Models;
using System;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using System.Threading;

namespace AzureManagementConsoleApp
{
    public class Program
    {
        static void Main()
        {
            ChangeWebSiteStatus();
            Console.ReadLine();
        }

        public static async void ChangeWebSiteStatus()
        {
            const string webSiteName = "createfromcode";
            const string webSpaceName = "eastasiawebspace";

            var cert = new X509Certificate2(@"Assets\ManagementTestCert.pfx", "<パスワード>");
            var credentials = new CertificateCloudCredentials("<サブスクリプションID>", cert);

            using (var client = CloudContext.Clients.CreateWebSiteManagementClient(credentials))
            {
                // まず Web サイトの状態を取得
                {
                    var parameters = new WebSiteGetParameters();
                    //以下を試したけど取れなかった。これなんだろ?
                    //{
                    //    PropertiesToInclude = new string[] { "WebSocketsEnabled", "PhpVersion" }
                    //};
                    var response = await client.WebSites.GetAsync(webSpaceName, webSiteName, parameters, CancellationToken.None);
                    Console.WriteLine("変更前, {0} のサイトモード    = {1} ", webSiteName, response.WebSite.SiteMode);
                    //以下二つは取れない(key がないので例外が出る)
                    //Console.WriteLine("変更前, {0} のWebScoketモード = {1} ", webSiteName, response.WebSite.SiteProperties.AppSettings["WebSocketsEnabled"]);
                    //Console.WriteLine("変更前, {0} のPHPバージョン   = {1} ", webSiteName, response.WebSite.SiteProperties.AppSettings["PhpVersion"]);
                }

                // Web サイトの構成情報を取るのはこっち
                {
                    var response = await client.WebSites.GetConfigurationAsync(webSpaceName, webSiteName, CancellationToken.None);
                    Console.WriteLine("変更前, {0} のWebScoketモード = {1} ", webSiteName, response.WebSocketsEnabled);
                    Console.WriteLine("変更前, {0} のPHPバージョン   = {1} ", webSiteName, response.PhpVersion);
                }

                // 構成を更新
                {
                    // PHP バージョンを 5.4-> 5.5, WebSocket を Enabled -> Disabled へ
                    var parameters = new WebSiteUpdateConfigurationParameters
                    {
                        PhpVersion = "5.5",
                        WebSocketsEnabled = false
                    };
                    var updateConfigurationResponse = await client.WebSites.UpdateConfigurationAsync(webSpaceName, webSiteName, parameters, CancellationToken.None);
                    //こっちには WebSite プロパティがない
                    Console.WriteLine("RequestId = {0}, StatusCode= {1} ", updateConfigurationResponse.RequestId, updateConfigurationResponse.StatusCode);
                }

                // Web サイトの状態を 無料 -> 共有 へ変更
                {
                    var parameters = new WebSiteUpdateParameters
                    {
                        SiteMode = WebSiteMode.Basic,
                    };
                    var response = await client.WebSites.UpdateAsync(webSpaceName, webSiteName, parameters, CancellationToken.None);
                    Console.WriteLine("変更後, {0} のサイトモード    = {1} ", webSiteName, response.WebSite.SiteMode);
                }
                // もっかい Web サイトの構成情報を取る
                {
                    var response = await client.WebSites.GetConfigurationAsync(webSpaceName, webSiteName, CancellationToken.None);
                    Console.WriteLine("変更前, {0} のWebScoketモード = {1} ", webSiteName, response.WebSocketsEnabled);
                    Console.WriteLine("変更前, {0} のPHPバージョン   = {1} ", webSiteName, response.PhpVersion);
                }
            }
        }
    }
}
  • 実行結果
変更前, createfromcode のサイトモード    = Limited
変更前, createfromcode のWebScoketモード = True
変更前, createfromcode のPHPバージョン   = 5.4
RequestId = a4f9803ff1a75c2db950db5d938b1ec6, StatusCode= OK
変更後, createfromcode のサイトモード    = Basic
変更前, createfromcode のWebScoketモード = False
変更前, createfromcode のPHPバージョン   = 5.5

*1:この辺はパケットキャプチャで確認したいところ