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

かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

Azure Mobile AppsでUWPを作ってみよう「手組編」

Azure UWP

過去記事

あらすじ

前回は、Mobile Apps Quickstartを使ってTodoListのひな型をダウンロードして、そいつに認証機能をつけてみました。 前回は全部自動で作られてたので、今回は手組してみようと思います。

サーバーサイドの作成

Mobile Appsのサーバーサイドは.NETかJavaScriptを選ぶことが出来ます。個人的には.NETが好みなんですが、流れを見てるとJavaScript推しに見えるので、ちょっと捻くれてTypeScript 2.0(現時点でRC)で組んでみたいと思います。開発ツールはVisual Studio Codeを使います。

必要なもののインストール

Node.js

node.jsが必要です。インストールしておきましょう。

Node.js

TypeScript

node.jsを入れたら、コマンドプロンプトあたりで以下のコマンドを叩いてTypeScriptを入れておきます。

npm install -g typescript@rc

(2.0正式版が出たら@rcいらない)

Visual Studio Code

開発に使います。

Visual Studio Code

インストールしたらユーザー設定で以下のものを追加してTypeScript 2.0を使うようにします。(2.0がリリースされてVS Codeが普通に対応してたら不要な設定)

// 既定の設定を上書きするには、このファイル内に設定を挿入します
{
    "typescript.tsdk": "C:\\Users\\ユーザー名\\AppData\\Roaming\\npm\\node_modules\\typescript\\lib"
}

SQL Server Express 2016/SQL Server Management Studio

開発用のDBとして使います。入れておきましょう。

Download Microsoft® SQL Server® 2016 Express from Official Microsoft Download Center

Download SQL Server Management Studio (SSMS)

DB本体と、管理ツールです。

プロジェクト?の作成

プロジェクトという概念があるのかは謎ですが作成していきます。コマンドプロンプトかPowerShellで任意のフォルダを作成します。ここではOkazukiTodoAppという名前にしました。

code .

上記のように打ち込んでVisual Studio Codeを起動します。Ctrl + Shift + PView: Toggle Integrated Terminalを選んでターミナルを表示します。以下のように打ち込みます。

npm init

プロジェクト名だけ全部小文字のokazukitodoappにしてあとはEnterで終わらせます。package.jsonが作成されます。続けてTypeScriptの初期化を行います。

tsc --init

生成されたtsconfig.jsonを確認すると以下のようになってると思います。

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es5",
        "noImplicitAny": false,
        "sourceMap": false
    },
    "exclude": [
        "node_modules"
    ]
}

package.jsonも以下のようにmainを変えておきます。

{
  "name": "okazukitodoapp",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

必要なライブラリのインストール

必要なライブラリなどのインストールを行います。Mobile Appsはexpressと、それを拡張したazure-mobile-appsというライブラリなのでそれを入れます。

npm install --save express azure-mobile-apps

続けて、型定義ファイルもとってきます。これもTypeScript 2.0からはnpmでいけます。

npm install --save @types/express @types/azure-mobile-apps

エントリポイントの作成

そしてapp.tsを作成して以下のようなコードを書きます。定型句です。

import * as express from 'express';
import * as azureMobileApps from 'azure-mobile-apps';

let app = express();
let mobile = azureMobileApps();

mobile.tables.import('./tables');
mobile.tables.initialize()
    .then(() => {
        app.use(<any>mobile);
        app.listen(process.env.PORT || 3000);
    });

型定義があるので割とすらすら書けます。唯一イケてないのがapp.useのところで、mobileを渡すのですが、そのまま渡すとエラーになります…。とりあえずanyにキャストしてお茶を濁しています。

テーブルの定義

次にテーブルを定義します。

tablesフォルダを作って(app.tsでimportしてるやつ)TodoItem.tsファイルを作ります。

import * as azureMobileApps from 'azure-mobile-apps';

let table = azureMobileApps.table();

// 動的生成しない
table.dynamicSchema = false;
// テーブルの定義
table.columns = {
    text: "string",
    complete: "boolean"
};

module.exports = table;

そして、Ctrl + Shift + Bでビルドをします。タスクランナーを構成するか聞かれるので構成します。TypeScripttsconfig.jsonを使うやつを選びます。これで、もう一度Ctrl + Shift + Bを押すとビルドされてjsが出力されます。

次にF5を押して実行します。初回はどういう風に実行するか聞かれるのでNode.jsを選びます。

実行するとエラーになります。これはDBを構成してないと自動的にSQLiteが使われるためです。とりあえず一度停止して、以下のコマンドをうってsqlite3をインストールします。

npm install --save sqlite3

気を取り直してもう一度F5を押すと今度は起動します。

クライアントサイドの作成

サーバーサイドが出来たのでクライアントサイドを作ります。Blank App(Universal Windows)のプロジェクトを作ります。 プロジェクト名はOkazukiTodoApp.Clientにしました。 NuGetから以下のパッケージを追加します。これがMobile Appsのライブラリになります。

  • Microsoft.Azure.Mobile.Client

そして、こんな感じの画面を組みます。

<Page x:Class="OkazukiTodoApp.Client.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:OkazukiTodoApp.Client"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">

    <Page.BottomAppBar>
        <CommandBar>
            <AppBarButton Icon="Add"
                          Label="Add"
                          Click="ButtonAdd_Click" />
            <AppBarButton Icon="Refresh"
                          Label="Refresh"
                          Click="ButtonRefresh_Click" />
        </CommandBar>
    </Page.BottomAppBar>
        
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <ListView x:Name="ListViewTodos"  
                  Grid.Row="0" />
        <TextBox x:Name="TextBoxInput"
                 Grid.Row="1" />
    </Grid>
</Page>

画面を組んだらコードビハインドを以下のようにします。

using Microsoft.WindowsAzure.MobileServices;
using Newtonsoft.Json;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace OkazukiTodoApp.Client
{
    public sealed partial class MainPage : Page
    {
        private MobileServiceClient Client { get; } = new MobileServiceClient("http://localhost:3000");

        public MainPage()
        {
            this.InitializeComponent();
        }

        private async void ButtonAdd_Click(object sender, RoutedEventArgs e)
        {
            await this.Client.GetTable<TodoItem>().InsertAsync(new TodoItem { Text = this.TextBoxInput.Text });
        }

        private async void ButtonRefresh_Click(object sender, RoutedEventArgs e)
        {
            var items = await this.Client.GetTable<TodoItem>().CreateQuery().ToListAsync();
            this.ListViewTodos.ItemsSource = items;
        }
    }

    public class TodoItem
    {
        [JsonProperty(PropertyName = "id")]
        public string Id { get; set; }
        [JsonProperty(PropertyName = "text")]
        public string Text { get; set; }
        [JsonProperty(PropertyName = "complete")]
        public bool Complete { get; set; }

        public override string ToString()
        {
            return $"{this.Text}: {this.Complete}";
        }
    }
}

TodoItemクラスでサーバーに定義したテーブルと同じ構造のデータを用意しています。それをつかってMobileServiceClientに、先ほど作成したlocalhost:3000に対してアクセスするようにしています。

実行して動作確認

起動してHello worldと入力して+ボタンを押します。

f:id:okazuki:20160908202318p:plain

そしてRefreshボタンを押すと以下のようにデータが取得できます。

f:id:okazuki:20160908202419p:plain

SQL Serverでの動作

現状インメモリにデータを格納してる状態なので、SQL Serverに保存するようにしたいと思います。

1433番ポートで外部からの接続を許可するように構成したSQL Server 2016 Express Edition(ここに手順があります。方法: ローカル コンピューター上で開発データ ストアとして SQL Express を使用する)にSQL Server Management Studioでアクセスします。 okazukitodoapp-dbという名前でデータベースを作成します。そして、適当にSQLサーバー認証でアクセスできるユーザーを追加します。

そして、azureMobile.tsというファイルを作って以下のような内容にします。

module.exports = {
    cors: {
        origins: ['localhost']
    },
    data: {
        provider: 'mssql',
        server: '127.0.0.1',
        database: 'okazukitodoapp-db',
        user: 'ユーザー名',
        password: 'パスワード'
    },
    logging: {
        level: 'verbose'
    }
};

このファイルは、Gitで管理するときは.gitignoreに入れておくといいでしょう。

npmでmssqlパッケージを入れます。

npm install --save mssql

ビルドして実行します。(ビルド忘れないように)ログにこんなのが表示されたら成功です。

node --debug-brk=24556 --nolazy out\app.js 
Debugger listening on [::]:24556
2016-09-08T11:51:13.622Z - verbose: Adding table definition for TodoItem
2016-09-08T11:51:13.806Z - info: Creating table TodoItem

UWPアプリを起動して適当にデータを追加してみてSQLServer Management Studioでデータを確認してみます。こんな感じでデータが入ってれば成功です。

f:id:okazuki:20160908205412p:plain

Azureに発行しよう

そして、Azureに発行してみようと思います。色々な方法がありますが、ここではGitを使ってやってみたいと思います。

Mobile Appを新規作成します。customokazukitodoappで作成しました。

f:id:okazuki:20160908205654p:plain

DBを構成します。MOBILEData Connectionsを選びます。 そしてAddを選びます。

こんな感じでSQL Databaseを作ります。

[f:id:okazuki:20160908210049p:plain

Data Connectionsの作成には少し時間がかかるので待ちます。

待ってる間にDeployment credentialsを選んでユーザー名をパスワードを設定します。ここで設定したユーザー名をパスワードをGitでプッシュするときに使います。

Deployment optionsを選んで、Choose sourceLocal Git Repositoryを選びます。

f:id:okazuki:20160908211003p:plain

OKをすると、OverviewにGitのリポジトリのパスが表示されるようになるので、控えておきます。

f:id:okazuki:20160908211218p:plain

VS CodeでGitリポジトリを初期化します。azureMobile.tsとazureMobile.jsはignoreにしておきましょう。

.gitignoreはこんな感じ。

node_modules/
azureMobile.ts
azureMobile.js

本当はjs自体入れたくないけど、AzureにJavaScript上げないといけないので泣く泣く入れてます。

そして、node.jsのバージョンは、今回6.3.1を使ってるのですが、Azureでデフォルトは4系なので6.3系を指定します。6.3.0が使えるらしいので、package.jsonにenginesを追加しておきます。ついでに使用していないsqlite3も消しておきましょう。

{
  "name": "okazukitodoapp",
  "version": "1.0.0",
  "description": "",
  "main": "out/app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "engines": {
    "node": "6.3.0"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@types/azure-mobile-apps": "^2.0.28",
    "@types/express": "^4.0.32",
    "azure-mobile-apps": "^2.2.3",
    "express": "^4.14.0",
    "mssql": "^3.3.0"
  }
}

azureという名前で先ほどのGitのリポジトリのURLをリモートに追加します。コマンドでやるとこんな感じ。

git remote add azure https://okazuki@customokazukitodoapp.scm.azurewebsites.net:443/customokazukitodoapp.git

そしてプッシュします。コマンドでやると以下のような感じ。

git push azure master

ユーザー名をパスワードを聞かれるので先ほど設定した奴を入れましょう。

暫くログが流れます。

remote: Deployment successful.       

と出れば成功だと思います。

MainPage.xaml.csのMobileServiceClientのURLを本番に書き換えて実行します。

private MobileServiceClient Client { get; } = new MobileServiceClient("http://customokazukitodoapp.azurewebsites.net");

何個かデータを突っ込んでみたあとにSQL DatabaseにSQL Server Management StudioでつないでTodoItemテーブルにデータが入っていれば成功です。

f:id:okazuki:20160908221530p:plain