OSC (オープンソースカンファレンス) 2018 北海道 ~ ハンズオンの補足

今回のハンズオンで触れたの補足記事になります。参加者向けとなります。

https://osc2018-kitaazu.azurewebsites.net/

の下部にある share からスライドを見ていただくとわかるかもしれません。

要約

今回の実装したところは以下のようになります。
Basic C# テンプレートを元に、特定のアクティビティ (メッセージ)で、添付ファイル (Attachment Class)があるときだけ、Bot Frameworkが提供してくれているイメージのURLを引数として、Custom Vision – Custom Vision Prediction 2.0 – PredictImageUrl を呼び出し、結果を文字列にして返す。

Bot Service

ボットの実装をぐっと楽にしてくれるものになります。
https://docs.microsoft.com/en-us/azure/bot-service/?view=azure-bot-service-3.0

Bot Framework Bot Builder (https://github.com/Microsoft/BotBuilder)

また、ハンズオン中にこれはどういうメンバーを持っているか?といったような質問がありました。リファレンスとして参照するものは、. NET SDK のものを見ていただければよいかと思います。(下のリンク)

https://docs.microsoft.com/en-us/azure/bot-service/dotnet/bot-builder-dotnet-overview?view=azure-bot-service-3.0

C# スクリプト

今回のハンズオンでは、.NET を扱えて、Visual Studio が不要な C# スクリプト(.csx)をベースに、API呼び出しを追加しました。この記事(++C++; // 未確認飛行 C – C#スクリプト実行)を参考にするとわかりやすいかもしれません。 #r で必要とするアセンブリの参照を追加すること。 #load で追加した csx ファイルを読み込んでいます。それ以外は、スクリプトではない、C#と全く同じになります。

Visual Studio を使って、C#として同じこともできますので、Visual Studio をお持ちの方はそちらのほうが、ぐっと楽になります。

Custom Vision プレビュー

ボットの判断能力となるものになります。概要としては、こちらを
これは、画像と分類を教えてあげることで勉強してくれます。
成果として、画像を分類してくれます。教えられたそれぞれの分類に対して、0 ~ 1.00のスコアが与えられます。展示・ハンズオン用の「ラムネ判別機」は、ラムネ、ボトル、チュアブル、飲み物、フローズン、などの分類を教えました。
これは、ブラウザで作ることができるため、今回のハンズオンにぴったりでした。また、受け取った画像は、学習データとして蓄積させていくことができます。もちろん、学習データとして蓄積しないようにもできます。
ラムネ判別機の画像は100程度からスタートして、展示中も学習を続けて130枚程度になりました。

App Service

Web Chat を配置したものになります。概要としては、こちらを
見ていただくとわかりますが、本来はアプリケーションを動作させるものです。
が、今回はオンラインでの編集機能を使いたいためこれを利用しました。
App Service Editor

Azure Functions

ボットの本体の部分です。
しかし、これは、Bot Service (Functions Bot)の一部となります。
概要はこちら

まとめ

というわけで、実はこのハンズオンに参加された方、30分弱で大きく3つ以上のサービスに触れていました。
目的としては、動くものができる!としていましたので、それぞれの使い方を触れる時間はありませんでした。
なお、プレビューの機能も含まれていることは注意してください。
もしどこかの機能に興味があれば、ぜひ、チャレンジしてみてください!
それでは!

Azure Functions Runtime

Build 2017
の中でひそかに更新されたBlogがあった。

Introducing Azure Functions Runtime preview

なんというか、Runtime?ってどういうことだろうと思って開いてみたところ。

Azure Functionをオンプレミスでも動かせるようにできるものらしい。

 

最低要件とか

細かいドキュメントは、「Azure Functions Runtime Overview」あたりから

Windows Server 2016 or Windows 10 Creators Update with access to a SQL Server instance.

Windows Server 2016 または、Windows 10 Creators Updateとなっている。
このあたり、Windows Containerに依存している部分があるためと考えられそうだ。また、SQL Serverへの接続も必要と。

機能

このRuntimeが持つ機能は大きく二つ

「Azure Functions Management Role」
ポータルのような管理する機能を提供する

「Azure Functions Worker Role」
FunctionをWindows Containerに展開して実行する

ドキュメントでは、VisualStudio 2017からの直接デプロイもできるとはなっている。

ダウンロードは、Blog記事より下部にある

How do I get started?

Please download the Azure Functions Runtime installer.

からできた。

ちょっとだけ

以下、Windows Server 2016 へのインストールと、インストール後の画面
SQL Serverへの接続を構成しない限り動作しないようだ。
インストール後は再起動が必要となった。

スライドショーには JavaScript が必要です。

Microsoft TranslatorのAPIを使うに当たって・・

Azureの認証が必要となるために、単純な呼び出しでは利用できない様子。

https://github.com/MicrosoftTranslator/GetAzureToken

ここのソースが参考になった。

Functionsで利用する場合は

https://github.com/MicrosoftTranslator/GetAzureToken/blob/master/AzureAuthToken.cs

Tokenの取得が必要となるため、上記を参考にするとよさそうだ。
リクエストがTokenの取得と、取得したTokenを渡すAPI呼び出しになっていることに注意が必要。

 

 

Visual Studio Tools for Azure Functions の修正版

Azure Functions 向けの拡張機能を入れたところで、.NET Coreのプロジェクトがだめになるっていうものに対する修正版が出てたようです。

https://blogs.msdn.microsoft.com/webdev/2016/12/01/visual-studio-tools-for-azure-functions/

Update 12-6-16 @5:00 PM: Updated version of the tools are available that fix the ability to open .NET Core projects with Azure Functions tools installed. Install the updated version over your old version to fix the issue, there is no need to uninstall the previous copy.

というわけで、入れてみたところ・・・

2016-12-10

インストール完了。
プロジェクトの新規作成で、ASP.NET Coreのプロジェクトテンプレートから作成したみところ、無事にできました。

2016-12-10-2

良かった良かったー

風邪っぽい・・・?VS2015の拡張機能

Microsoft Azure2 Advent Calendar 2016 の6日目の記事です。
.NET Core Advent Calendarの6日目の記事です。


2016-12-10追記
Visual Studio Tools for Azure Functions の修正版が出たようで、解消しました。

両方空いていたのと、両方を好きな人はこれから私と悲しい気持ちを味わう前に楽しくなってもらえればという願いを込めて書きました。
相変わらず、しょうもないネタなのですが・・・お時間あればお付き合いください。
Visual Studio 2015の話になります。

季節の変わり目で、咳が止まらず目が覚めて何気なく.NET Coreプロジェクトを作ろうとしたら・・・

2016-12-05-1

2016-12-05-2

あ、、、あれれ?コンソールだめなら、Webは・・・?

2016-12-05-3

2016-12-05-4

 

うーむ、VS2017 RCと共存してるからかなぁ・・・とか思いつつ、既存の.NET Coreアプリを開いてみたところ・・・

=====================
2016/12/04 5:47:00
Recoverable
System.Exception: ディスク上のプロジェクトファイルの検出中に次のエラーが発生しました。Could not load file or assembly 'Microsoft.VisualStudio.ProjectSystem.DotNet, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. 指定されたファイルが見つかりません。。
   at Microsoft.VisualStudio.ProjectSystem.DotNet.Common.FileMirroring.SourceItemsInMemoryProject.<InitializeFromDiskAsync>d__54.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.VisualStudio.ProjectSystem.DotNet.Common.FileMirroring.SourceItemsInMemoryProject.<Creator>d__52.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.VisualStudio.ProjectSystem.UnconfiguredProjectImpl.AutoLoadMethodStateMachine.<<StartExecution>b__6_0>d.MoveNext()
===================

どうやら風邪がうつったようです

いやいやそんなわけはなく・・・いろいろ調べてみたところ・・・
どうやら、Visual Studio Tools for Azure Funtionsの問題として認識されてるよというところまでは見つけました。

https://blogs.msdn.microsoft.com/webdev/2016/12/01/visual-studio-tools-for-azure-functions/

Warning: We have discovered that installing this Preview breaks the ability to create or open .NET Core projects in Visual Studio 2015.  We are currently investigating, and will make a fix available as soon as it is ready.  In the meantime, do not install this on any machines where you plan to work with .NET Core projects.

.NET Coreプロジェクトを扱うことができなくなってしまうということで、対策をがんばってるそうです。

そう・・・思えばFunctionsへの浮気心が、.NET Coreとの距離を近づけたのかもしれない・・・

そうか、浮気といえば・・・電話番号は二つ・・・つまり、マシンをもう一つAzureで作ればいいじゃない!
この発想には賛否両論あると思いますが…

というわけで、デプロイ!!
で、さりげなく機能紹介。

2016-12-05-5

というわけで、デプロイできた仮想マシンのブレードを開くと、
Automation スクリプトというのがあるのでそこを選択すると出てくるものです。
これは、ご存知の方多いとは思いますが、ARMというテンプレートで、この仮想マシンと同じものを再現するために使える逆起しの設計書みたいな状態です。
ただ、エラーが出てる通り、この仮想マシンに設定した自動シャットダウンと、仮想マシン拡張の診断機能は含まれていません。なので100%ではないですが、このJSONを1から作るよりも、一度作ってみたものをもとにJSON取得して、修正。
ARMとしてテンプレートデプロイをするというシナリオが近道のような気がします。

 

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "virtualMachines_vm20161206_adminPassword": {
            "defaultValue": null,
            "type": "SecureString"
        },
        "virtualMachines_vm20161206_name": {
            "defaultValue": "vm20161206",
            "type": "String"
        },
        "networkInterfaces_vm20161206128_name": {
            "defaultValue": "vm20161206128",
            "type": "String"
        },
        "networkSecurityGroups_vm20161206_nsg_name": {
            "defaultValue": "vm20161206-nsg",
            "type": "String"
        },
        "publicIPAddresses_vm20161206_ip_name": {
            "defaultValue": "vm20161206-ip",
            "type": "String"
        },
        "virtualNetworks_vm20161206_vnet_name": {
            "defaultValue": "vm20161206-vnet",
            "type": "String"
        },
        "storageAccounts_vm20161206diag122_name": {
            "defaultValue": "vm20161206diag122",
            "type": "String"
        },
        "storageAccounts_vm20161206disks246_name": {
            "defaultValue": "vm20161206disks246",
            "type": "String"
        }
    },
    "variables": {},
    "resources": [
        {
            "comments": "リソース '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/vm20161206/providers/Microsoft.Compute/virtualMachines/vm20161206' から一般化されました。",
            "type": "Microsoft.Compute/virtualMachines",
            "name": "[parameters('virtualMachines_vm20161206_name')]",
            "apiVersion": "2015-06-15",
            "location": "japaneast",
            "properties": {
                "hardwareProfile": {
                    "vmSize": "Standard_F8s"
                },
                "storageProfile": {
                    "imageReference": {
                        "publisher": "MicrosoftVisualStudio",
                        "offer": "VisualStudio",
                        "sku": "VS-2015-Ent-VSU3-AzureSDK-29-Win10-N",
                        "version": "latest"
                    },
                    "osDisk": {
                        "name": "[parameters('virtualMachines_vm20161206_name')]",
                        "createOption": "FromImage",
                        "vhd": {
                            "uri": "[concat('https', '://', parameters('storageAccounts_vm20161206disks246_name'), '.blob.core.windows.net', concat('/vhds/', parameters('virtualMachines_vm20161206_name'),'20161204060340.vhd'))]"
                        },
                        "caching": "ReadWrite"
                    },
                    "dataDisks": []
                },
                "osProfile": {
                    "computerName": "[parameters('virtualMachines_vm20161206_name')]",
                    "adminUsername": "watashi.kanrisha",
                    "windowsConfiguration": {
                        "provisionVMAgent": true,
                        "enableAutomaticUpdates": true
                    },
                    "secrets": [],
                    "adminPassword": "[parameters('virtualMachines_vm20161206_adminPassword')]"
                },
                "networkProfile": {
                    "networkInterfaces": [
                        {
                            "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('networkInterfaces_vm20161206128_name'))]"
                        }
                    ]
                }
            },
            "resources": [],
            "dependsOn": [
                "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_vm20161206disks246_name'))]",
                "[resourceId('Microsoft.Network/networkInterfaces', parameters('networkInterfaces_vm20161206128_name'))]"
            ]
        },
        {
            "comments": "リソース '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/vm20161206/providers/Microsoft.Network/networkInterfaces/vm20161206128' から一般化されました。",
            "type": "Microsoft.Network/networkInterfaces",
            "name": "[parameters('networkInterfaces_vm20161206128_name')]",
            "apiVersion": "2016-03-30",
            "location": "japaneast",
            "properties": {
                "ipConfigurations": [
                    {
                        "name": "ipconfig1",
                        "properties": {
                            "privateIPAddress": "10.0.0.4",
                            "privateIPAllocationMethod": "Dynamic",
                            "publicIPAddress": {
                                "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddresses_vm20161206_ip_name'))]"
                            },
                            "subnet": {
                                "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworks_vm20161206_vnet_name')), '/subnets/default')]"
                            }
                        }
                    }
                ],
                "dnsSettings": {
                    "dnsServers": []
                },
                "enableIPForwarding": false,
                "networkSecurityGroup": {
                    "id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_vm20161206_nsg_name'))]"
                }
            },
            "resources": [],
            "dependsOn": [
                "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddresses_vm20161206_ip_name'))]",
                "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworks_vm20161206_vnet_name'))]",
                "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_vm20161206_nsg_name'))]"
            ]
        },
        {
            "comments": "リソース '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/vm20161206/providers/Microsoft.Network/networkSecurityGroups/vm20161206-nsg' から一般化されました。",
            "type": "Microsoft.Network/networkSecurityGroups",
            "name": "[parameters('networkSecurityGroups_vm20161206_nsg_name')]",
            "apiVersion": "2016-03-30",
            "location": "japaneast",
            "properties": {
                "securityRules": [
                    {
                        "name": "default-allow-rdp",
                        "properties": {
                            "protocol": "TCP",
                            "sourcePortRange": "*",
                            "destinationPortRange": "3389",
                            "sourceAddressPrefix": "*",
                            "destinationAddressPrefix": "*",
                            "access": "Allow",
                            "priority": 1000,
                            "direction": "Inbound"
                        }
                    }
                ]
            },
            "resources": [],
            "dependsOn": []
        },
        {
            "comments": "リソース '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/vm20161206/providers/Microsoft.Network/publicIPAddresses/vm20161206-ip' から一般化されました。",
            "type": "Microsoft.Network/publicIPAddresses",
            "name": "[parameters('publicIPAddresses_vm20161206_ip_name')]",
            "apiVersion": "2016-03-30",
            "location": "japaneast",
            "properties": {
                "publicIPAllocationMethod": "Dynamic",
                "idleTimeoutInMinutes": 4
            },
            "resources": [],
            "dependsOn": []
        },
        {
            "comments": "リソース '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/vm20161206/providers/Microsoft.Network/virtualNetworks/vm20161206-vnet' から一般化されました。",
            "type": "Microsoft.Network/virtualNetworks",
            "name": "[parameters('virtualNetworks_vm20161206_vnet_name')]",
            "apiVersion": "2016-03-30",
            "location": "japaneast",
            "properties": {
                "addressSpace": {
                    "addressPrefixes": [
                        "10.0.0.0/24"
                    ]
                },
                "subnets": [
                    {
                        "name": "default",
                        "properties": {
                            "addressPrefix": "10.0.0.0/24"
                        }
                    }
                ]
            },
            "resources": [],
            "dependsOn": []
        },
        {
            "comments": "リソース '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/vm20161206/providers/Microsoft.Storage/storageAccounts/vm20161206diag122' から一般化されました。",
            "type": "Microsoft.Storage/storageAccounts",
            "sku": {
                "name": "Standard_LRS",
                "tier": "Standard"
            },
            "kind": "Storage",
            "name": "[parameters('storageAccounts_vm20161206diag122_name')]",
            "apiVersion": "2016-01-01",
            "location": "japaneast",
            "tags": {},
            "properties": {},
            "resources": [],
            "dependsOn": []
        },
        {
            "comments": "リソース '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/vm20161206/providers/Microsoft.Storage/storageAccounts/vm20161206disks246' から一般化されました。",
            "type": "Microsoft.Storage/storageAccounts",
            "sku": {
                "name": "Premium_LRS",
                "tier": "Premium"
            },
            "kind": "Storage",
            "name": "[parameters('storageAccounts_vm20161206disks246_name')]",
            "apiVersion": "2016-01-01",
            "location": "japaneast",
            "tags": {},
            "properties": {},
            "resources": [],
            "dependsOn": []
        }
    ]
}

このテンプレートを見て、何をデプロイしたか分かった人はすごい!

で、話は戻りまして・・・こうしてどちらかの環境用のマシンを分けておくと、何かと便利なので、あまり使ってないサブスクリプションを持ってる人とかはどうでしょうか?

まとめ

こんな状態でもツールをリリースして、たたかれる覚悟でも一歩でも進もうとしていることに私はすごいことなんじゃないかと思っています。

enjoy azure !
enjoy .NET Core !

Visual Studio 2015 のAzure FunctionsでStartしたときのUAC

Microsoft Azure2 Advent Calendar 2016 の3日目の隙間に向けて・・・隙間なネタを・・・!

開始するたびにダイアログがぽこぽこ上がってくるこれ・・・

UACを切ってしまえば・・・でもいいのだけど。それはそれで不安があるしとか思いつつ、もう一ついけそうだと思ってたのが、Visual Studioを管理者モードで起動する

2016-12-04-1

こうすると、親プロセスであるVisual Studioが管理者状態で動いていているので、そこから開始されるFunctionsのローカル実行のプロセスも自動的に管理者権限で動いてくれるということで、UACのダイアログは出てこなくなる。

ただ、Visual Studioに特権が与えられるので、それはそれで不安になることもあるかもしれない。

クリスマス近いんだねー

(メモ)Visual Studio 2015 の Azure Functions プロジェクトに 参照サービスを追加する

Functions単体では、ただコードを書いて、日付を返すとかはできますが、それだけでは、日付を返すとか文字列を変換するとかのことはできても、それは普通にローカルで動くプログラムでも得られるわけで、あまり意味がありません。
Functionsのプロジェクトを他のサービスに接続してみます。

 

プロジェクトのコンテキストメニュー(失敗)

ソリューションエクスプローラー>Functionsプロジェクト>コンテキストメニュー>追加>Connected Service

2016-12-03-1

追加用の画面が表示される
2016-12-03

Azure Storageを選ぶ
2016-12-03-2

既存を選ぶか、Create a New Storage Accountで新規に追加

2016-12-03-3

  1. Azure サブスクリプション を関連付けられているアカウントを選択
  2. サブスクリプションを選択
  3. Storage Account のURLになるものを入力
  4. お好みで料金体系・サービス体系を選択
  5. リソースグループを選択(ここで新規で作ることもできる)
  6. Locationを選択

Azure Storageの画面でAddとしてみると・・・

2016-12-03-4

NuGetのパッケージを追加できずにエラー。
というわけで、この方法ではだめな様子。
ひとまずフィードバックを送信。

functions の場合、プロジェクトの参照というよりは、bindingの定義があってという感じなのもあるかもしれないのでひとまずこの方法ではなさそう。

Functionsの追加から

試しにFunctionの追加から、
テンプレートは、FaceLocatorという、Blobストレージにある画像から顔がある四角形領域を返してくれるもの。

2016-12-03-5

ストレージアカウントの接続文字列を入力する欄が赤くなってますので、ポータルから引っ張ってくる。

2016-12-03-6

この接続文字列は絶対に公開しないように・・・
このように公開してしまった場合は、アカウントを消すか、接続文字列を再生成する必要が出てくる。その場合既存の接続文字列は使えなくなるので、いろいろ面倒。

追加した「FaceLocatorCSharp」の
function.json

{
  "bindings": [
    {
      "type": "blobTrigger",
      "name": "image",
      "path": "images/{name}.jpg",
      "connection": "DefaultEndpointsProtocol=https;AccountName=functionapp;AccountKey=xxxxxx;",
      "direction": "in"
    },
    {
      "type": "table",
      "name": "outTable",
      "tableName": "faceRectangle",
      "connection": "DefaultEndpointsProtocol=https;AccountName=functionapp;AccountKey=xxxxxx;",
      "direction": "out"
    }
  ],
  "disabled": false
}

このファイルにあるbindingsが、作ったfunctionsの入出力の定義そのものになっている。nameにある文字列がfunctionsのメソッドにある引数として以下のように

public static async Task Run(Stream image, string name, IAsyncCollector<FaceRectangle> outTable, TraceWriter log)
{
    ....
}

しかし・・・

F5デバッグ開始をしてみるもののエラーが発生してしまう。
かなり手詰まりではあるが、実際に動いているものがあるということはそこから得られるヒントがある・・・と信じて

ポータルから・・・

ポータルから生成したもののソースコードを見てみると

  {
  "bindings": [
    {
      "type": "blobTrigger",
      "name": "image",
      "path": "images/{name}.jpg",
      "connection": "functionappXXXX",
      "direction": "in"
    },
    {
      "type": "table",
      "name": "outTable",
      "tableName": "faceRectangle",
      "connection": "functionappXXXX",
      "direction": "out"
    }
  ],
  "disabled": false
}

といった形で、appSettings.jsonに設定されたものを指定しているようだ。
なので置き換えた。

それでもエラーはまだ残るため次に、テンプレート作成時には空となっていた
AzureWebJobsStorageおよびAzureWebJobsDashboardにも接続文字列を追加した

これは、ポータルで生成した場合は自動的に追加されているものだった。

FaceLocatorのキー

さらにわかったことがあって、テンプレート「FaceLocatorCSharp」では、VisionAPIを使うことになっているが、このための接続情報をappSettingsに追加してやる必要があった。

それがわかるコードはここで

        client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", Environment.GetEnvironmentVariable("Vision_API_Subscription_Key"));

「Vision_API_Subscription_Key」という設定値を必要としていたので、appSettings.jsonに追加した。

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=functionapp;AccountKey=xxxx",
    "AzureWebJobsDashboard": "DefaultEndpointsProtocol=https;AccountName=functionapp;AccountKey=xxxx",
    "Vision_API_Subscription_Key": "xxxxxxxxxxxxxxxxx",
    "functionapp": "DefaultEndpointsProtocol=https;AccountName=functionapp;AccountKey=xxxx"
  }
}

もちろんこれは使えるものではなく、
https://www.microsoft.com/cognitive-services/en-us/subscriptions
より取得する必要がある

 

 

Visual Studio の拡張機能として

まだ、このFunctionsの拡張機能はPreviewであり今後変わる可能性があると思うが、
現状動くポータルを正解としていけば動かす道は掴んでいけそうであることがわかった。

.funprojを覗いてみて・・・メモ

Visual Studioで読み込まれるプロジェクトファイルはXML形式で、ビルドするために何らかのtargetsファイルを読み込んでいたり、プロジェクトに設定されたファイルを記述していたりするので、のぞいてみた。

今後変わる可能性は十分にあるので、完全に自己満足or趣味

なんと!
ファイルはどれも関連づいていない。
プロジェクトのディレクトリにあるものはすべて一部となる様子。

ビルドの定義は、Micorosoft.AzureFunctions.targetsファイルにあるようで。
Debug|Any CPU
Release|Any CPU

内部の初期値では、.NET Framework 「v4.5.1」ただ、ビルドのログを見てる限りコンパイラが動いてなさそうなので、ダミーに近い。

MSBuildとしてのメインは、Publishなのかなぁという感じがした。

Publish

その中で
\bin
\obj
*.funproj
*.pubxml
*.user
に該当するファイル、フォルダーは対象外としている様子

デプロイするためのリソースは一時的
obj\PublishTemp\
に格納される
現状これは、パターンに該当しないファイル以外をコピーしている。

 

ソース管理

pubxmlファイルはデプロイ先の情報を持っているため、GitHubなどの公開されるソース管理では対象外としたほうがよさそうだ。

Visual Studio 用の Azure Functions拡張機能(Preview)

昨日、まだ出ないだろうと思ってとりあえずな記事書いたところで、
正式なFunctionsの拡張機能が出たようです。

https://blogs.msdn.microsoft.com/webdev/2016/12/01/visual-studio-tools-for-azure-functions/

 

注意点として

  • プレビューであること
  • Visual Studio 2015 Update 3用であること
  • Azure 2.9.6 .NET SDKがインストールされていること

プロジェクトテンプレート

FunctionApp1という名前で作ってみたところ、以下のようなファイルが

Properties
appsettings.json
FunctionApp1.funproj
host.json
Project_Readme.html

これだけだと、ファンクションそのものがないからの状態なんですが、
デバッグ開始(F5)してみると
Azure-Functions-Cliをダウンロードしてくるぞ?と聞かれました。
いいよとすると、コマンドプロンプトのように、ローカルホスト用であるfunc.exeが起動

Listening on http://localhost:7071/
Hit CTRL-C to exit...
Reading host configuration file 'c:\Projects\FunctionApp1\FunctionApp1\host.json'
Generating 0 job function(s)
Starting Host (HostId=sb-v2-functionapp1, Version=1.0.0.0, ProcessId=9404, Debug=False)
No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. config.UseServiceBus(), config.UseTimers(), etc.).
Job host started
File change of type 'Created' detected for 'c:\Projects\FunctionApp1\FunctionApp1\data'
Host configuration has changed. Signaling restart.
Stopping Host
Job host stopped
Reading host configuration file 'c:\Projects\FunctionApp1\FunctionApp1\host.json'
Generating 0 job function(s)
Starting Host (HostId=sb-v2-functionapp1, Version=1.0.0.0, ProcessId=9404, Debug=True)
No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. config.UseServiceBus(), config.UseTimers(), etc.).
Job host started
Debugger listening on [::]:5858

特に何もファンクションがないので、Jobは0となってます。

Functionsを追加

Blogに書かれているように
ソリューションエクスプローラー>プロジェクト>コンテキストメニュー>追加>New Azure Function

とすると、テンプレートがずらずらーっと並んでるので追加。
再びデバッグ開始で、

Listening on http://localhost:7071/
Hit CTRL-C to exit...
Reading host configuration file 'c:\Projects\FunctionApp1\FunctionApp1\host.json'
Generating 1 job function(s)
Starting Host (HostId=sb-v2-functionapp1, Version=1.0.0.0, ProcessId=7960, Debug=True)
Found the following functions:
Host.Functions.HttpTriggerCSharp

Job host started
Http Function HttpTriggerCSharp: http://localhost:7071/api/HttpTriggerCSharp

というわけで、ブレークポイントを設定してブラウザから
http://localhost:7071/api/HttpTriggerCSharp
にアクセスしてみると・・・

2016-12-02-1

おおー、変数展開、呼び出し履歴、タスク、診断ツール
と普通にいけてるじゃないですか!!
ローカル環境での実行なので、AzureFunctionsをデプロイしてなくてもいいし。
極端な話、ネットワークにつながってなくても書ける・・・かもしれない?

デプロイ

Blogに書かれているように
ソリューションエクスプローラー>プロジェクト>公開

AppServiceとしてを選ぶと、既存のFunctionsAppのみアイコン付きで出てきました。

2016-12-02-2

そのまま、AppServiceの感覚でデプロイ。

ここからは、せっかく書いた昨日の記事が生きてくるかもしれません。

 

 

Azure Functions ローカル Git リポジトリ

Azure Functionsのソースを、ローカルGit管理にしてしまう方法

少し試してポータルで編集している分には、それはそれでいいのですが
慣れた馴染んだエディタで編集したいとき、ローカルマシン上に持っていきたいというときにいいのかな?ということで。

1.ポータルから ローカル Git リポジトリ 設定

ポータルから対象のFunction Appを開き、
Function App の設定>継続的インテグレーションの構成

2016-11-26-4

 

デプロイのブレードが表示されるのでセットアップ

2016-11-26-5

 

ローカル Git リポジトリを選択

2016-11-26-6

ユーザー名パスワードを求められたら、
入力して忘れないようにしておきます。
(2回目以降入力が省略された!

2.ローカルマシンでclone

gitが入っている前提で

[FunctionAppName]には、作成時に入力したFunctionAppの名前を入れます

>git clone https://[FunctionAppName].scm.azurewebsites.net/

2016-11-26-7

忘れないようにしていたユーザー名とパスワードを入力

Cloning into '[FunctionAppName].scm.azurewebsites.net'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
Checking connectivity... done.

 

[FunctionAppName].scm.azurewebsites.net
というディレクトリが作成されていたらできあがり!

vscodeで開いた状態
ちゃんとコミットできる状態になってた

2016-11-26-8

注意点

ローカルGitリポジトリを設定すると、ポータルから編集できなくなります。

その場合、新しい関数を追加したいとき地道にファイルを追加するか。
一度ローカルGitリポジトリを無効にするか。
Azure-Functions-Cliを使う必要がありそうです。

※ローカルGitの切断・セットアップを繰り返しているうちに何かおかしくなった
※Visual Studio拡張機能が待ち遠しい