かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Azure Mobile Appsで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