App Service の CI/CDでビルドエラー

ちょっとはまったのでメモ。(そのうち改善されると思われる)

はまった環境: Visual Studio 2017 で .NET Framework 4.6.2 なクラスライブラリでNuGetなパッケージを使用しているC#プロジェクト(NuGetはPackageReferenceを参照する)と、それを参照するASP.NETなアプリ(1つのソリューションにASP.NETとクラスライブラリなプロジェクトがある状態)
はまった理由:  App Service上(Kudu上)で msbuild 15.x がないから(たぶん)

普通にApp Service上でCI/CDを使って(今回はLocal Git)上記なプロジェクトをデプロイ(git push)すると以下のようにNuGetで取得するパッケージに含まれるアセンブリが見つからない旨のエラーがでてビルドに失敗します。(nuget restoreやdonet restoreしてるにも関わらず)

省略
:
remote: D:\Program Files (x86)\dotnet\sdk\2.0.0-preview1-005977\Microsoft.Common.CurrentVersion.targets(1964,5): warning MSB3245: Could not resolve this reference. Could not locate the assembly "Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors. [D:\home\site\repository\web1\Shared\Shared.csproj]
:
以下略

カスタムデプロイスクリプトを使用するようにして、dotnet build や dotnet msbuild を使ってもダメです。
※Kudu上に現状Previewなmsbuildがありますがそちらを使ってもダメ
※ちなみにプロジェクトがPackage.configを参照するようになってたら問題なくビルドできます。PackageReferenceの場合のみおかしい。

回避策: クラスライブラリなプロジェクトファイル(.csproj)を新しい形式に変換する

変換は以下のURLを参考に。

最低限Project要素の属性を新しくして TargetFrameworkVersion を TargetFrameworkにしてv.4.6.2 とかを net462 とかにします。あとは不要な要素はバスバスけして、AssemblyInfo.csも消したりしました。
修正後、Visual Studio 2017上でちゃんとプロジェクトがロードできてビルドできればひとまず大丈夫かと思います。(Minなcsprojにしてから後でNuGetパッケージ追加したりもろもろいじってもよいかと思います。

変換後は dotnet build や dotnet publish で問題なくビルドできます。(つら)

過渡期な問題だと思いますが、もし嵌った人がいれば参考にしてもらえると。

ノートPCでも外付けGPUを使いたい

今使ってるノートPCでGPU使いたいなーとふと思いまして、外付けGPUユニットを買いました。
ノートPCのスペック的には外付けGPUもいけるだろうと思ってThunderbolt 3 (PCI Express Gen3 x 2レーン)で40Gbps双方向サポートされてる機種です。(DELLのXPS 13

外付けGPUを載せる筐体としてはPowerColor DEVIL BOXを選んでみました。(納期等の都合)
で、つないでみたのですがGPUを認識しないんですよね。TB3の設定みると
image
外付けGPUサポート:いいえ とか言われる始末。ファームが更新されたりドライバが更新されるのを心待ちしてたわけですが、親切なてんきちゃんに教えてもらったところ外付けの筐体側のファームを更新してみよう(人柱ヨロ)ということだったのでそのようにしてみました。

いろいろ見ると

As of 23-April-2017, TI83 (red) marked enclosures deliver only half their TB3-specced host-to-device bandwidth and are awaiting a firmware fix.

とか書いており、そのままじゃダメそうです。ただ

Allows eGPU detection in Windows for systems reporting “external GPUs supported: no” in the Intel Thunderbolt software.

とあるのでリンクにあるファーム更新ツールで強制的にファームを変えてみることにしました。※接続してファーム更新後OS再起動
TBソフトウェア上は外付けGPUサポートはいいえのままですが、ちゃんとGPU認識しました!やったね。

というわけでノートPCでも無事GPUが使えるようになりましたとさ。

※ GPUの取り外し時の確認ウィンドウがちゃんと描画されなかったりするし、稼働アプリがある状態で切断するとアプリ落ちるしその後の挙動が怪しい気もする(ノートPCのディスプレイの解像度がちゃんとならなかったり)ので、気軽に接続・切断はしにくくなった気もしますが概ね満足です。

Azure Functions で実行中にコンパイルするとどうなるの

裏でFunction Appが実行中のときにコンパイルして(コンパイルエラーになったりして)るときに実行中のものはどうなるのか、予想では別物なんで問題ないと思いますが一応。

検証用コード

using System.Net;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    log.Info($"Start ----");
    // parse query parameter
    string name = req.GetQueryNameValuePairs()
        .FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
        .Value;

    await Task.Delay(TimeSpan.FromSeconds(20));

    // Get request body
    dynamic data = await req.Content.ReadAsAsync<object>();

    // Set name to query string or body data
    name = name ?? data?.name;

   log.Info($"End ----------");
   return name == null
        ? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body")
        : req.CreateResponse(HttpStatusCode.OK, "Hello " + name);
}

HttpTriggerなC#のテンプレートにStartとEndのログと間にTask.Delayで処理止めてるだけのシンプルなやつです。
※ログにFunction Startedとか出るので無駄な気もするけど一応

手順的にはこんな感じ

1.  上記コードを実行する(適当に呼び出す)
2. Task.Delayしてる間にコードを適当に弄ってSaveしてコンパイルエラーにする
3. 結果を見る
4. そのまま再度呼び出す

実行結果はこんな感じになりました

2016-07-19T03:34:42.334 Function started (Id=14c91f2c-2490-437c-b461-258a13872d82)
2016-07-19T03:34:42.334 Start ----
2016-07-19T03:34:45.698 Script for function 'HttpTriggerCSharp1' changed. Reloading.
2016-07-19T03:34:45.698 Compiling function script.
2016-07-19T03:34:45.776 run.csx(14,13): error CS1002: ; expected
2016-07-19T03:34:45.776 run.csx(11,48): error CS0246: The type or namespace name 'aaaa' could not be found (are you missing a using directive or an assembly reference?)
2016-07-19T03:34:45.776 run.csx(14,13): error CS0103: The name 'data' does not exist in the current context
2016-07-19T03:34:45.776 run.csx(17,20): error CS0103: The name 'data' does not exist in the current context
2016-07-19T03:34:45.776 run.csx(14,5): warning CS0168: The variable 'dynamic' is declared but never used
2016-07-19T03:34:45.776 Compilation failed.
2016-07-19T03:35:02.334 End ----------
2016-07-19T03:35:02.334 Function completed (Success, Id=14c91f2c-2490-437c-b461-258a13872d82)
2016-07-19T03:35:27.915 Function compilation error
2016-07-19T03:35:27.915 run.csx(14,13): error CS1002: ; expected
2016-07-19T03:35:27.915 run.csx(11,48): error CS0246: The type or namespace name 'aaaa' could not be found (are you missing a using directive or an assembly reference?)
2016-07-19T03:35:27.915 run.csx(14,13): error CS0103: The name 'data' does not exist in the current context
2016-07-19T03:35:27.915 run.csx(17,20): error CS0103: The name 'data' does not exist in the current context
2016-07-19T03:35:27.915 run.csx(14,5): warning CS0168: The variable 'dynamic' is declared but never used
2016-07-19T03:35:27.915 Function completed (Failure)
2016-07-19T03:35:27.961 Exception while executing function: Functions.HttpTriggerCSharp1. Microsoft.Azure.WebJobs.Script: Script compilation failed.

StartとEndの間でコンパイル走ってエラーになってますが、Function Id=14c91f2c-2490-437c-b461-258a13872d82は継続して処理が完了してます。

その後再度呼び出してみるとコンパイルが完了してないので再度コンパイル→失敗→500エラーが返る、という感じです。

予想通りでしたね。なんかおかしい、という場合はぜひ追加の検証をお願いします。

Azure Management REST API用のBearerトークン

よく忘れるので。

$adal = "${env:ProgramFiles(x86)}\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Services\Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = "${env:ProgramFiles(x86)}\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Services\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll"
[System.Reflection.Assembly]::LoadFrom($adal)
[System.Reflection.Assembly]::LoadFrom($adalforms)
$adTenant = "<あなたのテナント>.onmicrosoft.com"
# well-known ID
$clientId = "1950a258-227b-4e31-a9cf-717495945fc2"
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
$resourceAppIdURI = "https://management.core.windows.net/"
$authority = "https://login.windows.net/$adTenant"
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $redirectUri, "Auto")
$authHeader = $authResult.CreateAuthorizationHeader()
# Write-Host "Bearer Token: $authHeader"
$authHeader | Out-File bearerToken.txt

これでBearerトークン出来上がり。認証はいつもの認証ダイアログ的なのが出るので安心です。
(要Azure PowerShell)

参考:Setting up PostMan to call the Azure Management APIs

Azure関連でMicrosoftのサポートを受けるには

これがソーシャルハラスメント!

とにかく、Azureのサポートに連絡してサポートを受ける方法です(日本語難しい)

続きを読む

Mac OS X で Azure CLI を使う

インストール方法とログイン方法など。最近MSアカウントに対応したのでログインまでのやり方です。

インストール

最初にnode.jsとnpmをインストールしましょう。公式サイトからダウンロード・インストールすればOKです。

あとはコンソールで以下のようにazure-cliをグローバルにインストールします。まぁお好みで。

sudo npm install -g azure-cli

最近だとDockerイメージもあるのでDocker導入済みならそちらを使うこともできます。公式ドキュメントを参照。

新しいバージョンへのUpdateはnpm update –g azure-cliとかでOKかと思います。

あとは通常どおりazureコマンドで利用できます。

image

ログイン

Azure CLIで操作する前にログインする必要があります。v0.9.10より古いバージョンでは証明書を使ったログインか、Azure AD上のアカウント(組織アカウント)を利用する必要がありました。

証明書を使用したログイン

もし手元に証明書がない場合は最初にダウンロードします。

azure account download

証明書ファイルが手に入ったらaccount importでインポートします。

azure account import "file location"

file locationのところにダウンロードした証明書を指定してください。あとは対象の証明書で管理できるサブスクリプションに対して操作が可能になります。

組織アカウントを使用したログイン

loginコマンドを使います。

azure login -u <account UPN (email address>

最近GAしたRBAC(ロールベースのアクセスコントロール)は組織アカウントだけが対象なのでこちらを使う必要があります。

Microsoftアカウントを使用したログイン

loginコマンドにユーザーIDを渡さないで実行します。

azure login

すると http://aka.ms/devicelogin にアクセスを促されます。コンソールはそのままでブラウザでURLにアクセスします。
image

コードの入力を促されるので、コンソールに表示されているコードを入力します。(Enter the code —–となっているところ)
image

あとは通常のサインインプロセスが走るのでMSアカウントでサインインします。まぁ組織アカウントでもサインインできますが。

無事サインインできればブラウザを閉じてもOKです。
image

どうでもいいですけど、Safariだとなんかフォントがいまいちですね。
しばらく待つとコンソール上でサインインが完了し、サブスクリプションの一覧が表示されます。
image

あとは通常通り操作が可能です。

その他

組織アカウントを多要素認証で保護している場合などは以下のようなエラーが発生します。

$ azure login -u xxxx@xxxxxx
info:    Executing command login
Password: ***************
+ Authenticating...
error:   Interactive login is required. Use 'azure login' to interactively login.
info:    Error information has been recorded to azure.err
error:   login command failed

この場合はMicrosoftアカウントでのサインイン方法でブラウザから認証を行ってください。

Universal Foldable Keyboard 買ってみた

Microsoftが最近だしたBluetoothな2つ折りキーボード、「Universal Foldable Keyboard」を買ってみました。

どういうものかは動画を見てもらえればわかりやすいかも。

特徴的な点をいくつか。

  • 水滴などついても平気
  • 2つのデバイスでペアリングできてワンボタンで切り替えできる
  • Windows / Android / iOS 対応
    • Windows 10, 8, 8.1
    • Windows Phone 8.1 Update 2
    • Apple iOS 7-8.1
    • Android 4.3-5.0
  • Bluetooth 4.0でHIDキーボードサポートのようです

感覚的にはCDケースぐらいの大きさ・厚みですね。デザインや作りはSurfaceのTypeCoverキーボードに似てます。Surface Pro3のTypeCoverが294グラムぐらい、Universal Foldable Keyboardが 183グラムぐらいですのでちょっと軽いです。
1回のフル充電で3か月使えるらしいです(試してないのでわからない)

2つのデバイスで共通で使えるのでよさそうと思って買ってみました。(最近iPadとSurface Pro 3を両方持ち歩くこと多いのでなんとかならないかなーと)
あわよくばWindows Phone(MADOSMA)1本でどうにかならないかなーと思ったわけですが。

とりあえず開封の儀を。

image

箱はコンパクトです。パカッと開いて本体取り出すときにキーボード本体を開くようになってる感じ。
image

付属品はプロダクトガイドと限定保証に関するドキュメント(Webから見れます)とUSBケーブルのみ。USBケーブルはSurfaceっぽく角がとがってる感じ。
そして本体裏面には…
image
事前にScott Hanselmanに教えてもらった通り(聞くなよ)、安心の技適マークが!これで日本でも安心です(マークなかったらBlog書かなかったね)

本体を開くと電源が入ります。
image
左上の丸い白い点が電源ランプで充電が不十分になると赤くなるようです。
image
左上の「1」「2」キーでデバイス切り替えです。それぞれ長押し3秒するとペアリング待ちになるので各デバイスで登録しましょう。右上の「OS」キーで接続先のデバイスをWindows/Android/iOSと切り替えれます。
image

右上側の横に充電用のUSBポートがあります。
image

日本でゲットするには?

技適あるのでそのうち(日本語配列のが)販売されそうですが、現状個人輸入です(US配列がほしい人は日本で販売されても輸入でしょう)。Microsoftストアだとなぜかエラーで購入できなかったので少し安いAmazon.comで買って転送しました(転送料考えると対して…)
買ったのが7月上旬ぐらいなのでだいぶ待ちました。Scott Hanselmanに励まされながら待つこと数週間という感じですね。

使用感

iOSの場合

特に問題なし。Homeキーも効くし、Lockや各ショートカットキーも問題ないです。iPadで試したんですが日本語環境にしてるので既定で日本語入力(ローマ字入力)状態でした。逆に英語にする方法わからない。(英語タイプして変換で直すぐらい?)

入力方式はCommand(Fn)キー+Spaceで切り替えられました。

Windowsの場合

普通に使えます。IMEの切り替えは(自分の環境だと)普通にALT+` でOK。音量やらロックやらもろもろのショートカットキーも問題ないです。
唯一の欠点はF1~のファンクションキーが無いことですね。割り切って使うかしないとだめです。代替ショートカットを完璧に覚えればなんとかなるかもしれません(そうか?)
2015/08/13追記:@osprey74さんに教えてもらいましたが、Fnキー+[1]~の数字キーでF1~の代わりになるようです。ちょっとコツいりますけど無いよりはいいですね!

Androidの場合

端末を持ってないので未評価

Windows Phoneの場合

MADOSMAで試してみました。(言語設定などは英語な状態)
Homeキーなどは使えませんでした。最初、英語しか入力できずよくわかりませんでしたが言語の追加で日本語入れておくと日本語入力な状態でタイプできました。(当初は右手側のセミコロンなどがずっとShiftキーおされた状態でコロンやダブルクォートしか入力できなくてかなり謎だった)
とはいえiOSと同じでIMEをオフにして直接英語入力な状態にはできませんでしたがまぁ。

(2015.12.18更新) Windows 10 Mobileだと言語切り替えもできるしファンクション系のキーも効きます。ALT+Tabでアプリの切り替えできるのはちょっと面白いw

Continuumが(MADOSMAでも使えて)できるようになったらこれだけでも最低限いろいろこなせますね。
(RDP使えるしほんとどうとでもなる)

入力のタッチなどはTypeCoverに近いのでそちらの感想に近いです。あとは真ん中でまっすぐに分かれてるのでそのあたり慣れですかね。キーピッチなどもそうです。

※Windows用にファンクションキーだけの細長いキーボードがあれば完璧なんじゃないだろうか(

個人的な使い方考察

  • Surface Pro 3のTypeCoverを外してUniversal Foldable Keyboardを持ち歩く
    • マウスはペンで代用もしくはBluetoothなマウス(Arc Touch)を持ち歩く?
    • がっつりファンクションキー使わなかったらいいかもしれない(勉強会参加とか)
    • もともとTypeCoverのタッチパッドが不満なのでこれでいいかも
  • iPadとMADOSMAだけ持ち歩く
    • Windows!なアプリケーション触りたいときはRDPする(緊急避難的な)
    • 近場にふらっと出かけたりするぐらいなら問題なさげ

という感じでちょっと使ってみようかと思います。

ASP.NETでCacheSeviceのOutputCache有効にすると超遅くなる現象

ASP.NET MVC4でAzure CacheServiceを使ったOutputCacheを有効にすると超遅くなる、という現象があって困ったのでメモ。

  1. 普通にASP.NET MVC4なアプリを作ります
  2. Install-Package Microsoft.WindowsAzure.Caching します
  3. Web.configを編集してOutputCacheプロバイダを設定します。
  4. 実行してみます

わかりやすいようにMiniprofilerも入れてみました。

image

ファッ!?

ローカルでこの遅さ。パーシャルViewとか使うともりもり+100msとかかかります。ありえない。

結論から言うとテンプレートに含まれる既定のMicrosoft.AspNet.Web.OptimizationがASP.NET既定のOutputCacheProvider以外はサポートしてないから処理に時間がかかる、ということでした。

NuGetでMicrosoft.AspNet.Web.Optimizationを1.1.0に更新すれば解決。

image

 

image

まともになりました。ふぅ。

教訓: 更新忘れずに。