NLogを.Net Standard/Coreで使用する
はじめに
.Net Core等は下記バージョンでお送りします。
- netstandard: 2.0
- netcoreapp: 2.2
- AspNetCore: 2.2.0
- NLog: 4.6.3
あらまし
NLogを使うとかは今更ではあるのですが
.Net CoreのExeアプリケーションからASP.net WebAPIアプリケーションで
NLogを使用する機会があったので、学習ついでの備忘録な感じのトピックです。
NLog.configの設定を外に出す
基本的な使い方は本家のGitHubやググったら山程でてくるので割愛…
NLogのログ出力の設定は、nlog.config
のXML形式ファイルに記述していく感じです。
が、これはいまいち好きじゃない。
と、いうのもASPにしてもCoreの普通のアプリにしてもjsonファイルにアプリケーション設定を記述していますし
あちこちのファイルに設定内容が散らばっているのも少し邪魔くさい。
ASP.netに関してはWebAppsがもっているアプリケーション設定で出力先をいろいろ設定できるようにすれば
CI/CD側の負担も軽くなるんでは?と思ったわけです。
(nlog.configのようなXMLファイルの設定もWebAppsの設定上でできるのであればいいのですが…ない?ですよね?)
NLog.configの構成
まずはXMLで設定されるNLogの構成を見てみます。
<?xml version="1.0" encoding="utf-8" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <targets> <target name="console" xsi:type="Console" /> </targets> <rules> <logger name="*" minlevel="Info" writeTo="console" /> </rules> </nlog>
これはLogの内容をConsoleに吐き出す設定ですが、target
で「何に対して」ログ出力するか指定し
rule
で 'target' に対して出力するログの内容を指定しています。
この場合、「Info
レベルからのログを Console
に出力する」という設定になっているわけですね。
NLogのTarget/Ruleの関係は、下記サイトが参考になりました。
NLogの設定を動的に指定する
こちらのサイトを参考にしました。
NLogをプログラマブルに初期化し動的に構成変更する - M12i.
NLog.Target
名前空間に ConsoleTarget
というClassが存在します。
NLog/ConsoleTarget.cs at dev · NLog/NLog · GitHub
他にも FileTarget
や DatabaseTarget
が存在します。
Classにあるプロパティを見てみると、Layout
やConnectionString
などXMLで設定するプロパティが存在するのが確認できます。
XMLの設定を確認しながら、TargetClassの同名プロパティに値を設定していく…という方法でNLogの設定ができそうです。
で、出来上がったのが下記です。
public static void ConsoleLogInit() { var conf = LogManager.Configuration; var console = new ConsoleTarget("console"); // consoleターゲットを生成 console.Layout = LogLayout; // アウトプットフォーマットレイアウトを設定 conf.AddTarget(console); // NLogの設定に生成したターゲット情報を追加 conf.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, console)); // consoleターゲットを使用するルールを追加 LogManager.Configuration = conf; // NLogの設定に反映 }
あとは同じように設定するだけ
TargetのClassにたいしてどのようなAPIが存在してどのような引数が求められているのかは
上記のGitHubのソースコードやドキュメントから抑えることができるので
ファイルに出力する場合やDBに出力する場合も同じように設定していくだけです。
ファイルに出力する場合はファイル名称やエンコードを指定するAPIが追加されていたりします。
public static void WriteLogToFileInit(string filePath, LogLevel targetLogLevel) { var conf = LogManager.Configuration; var file = new FileTarget("file"); file.Encoding = Encoding.UTF8; file.FileName = filePath; file.Layout = LogLayout; conf.AddTarget(file); conf.LoggingRules.Add(new LoggingRule("*", targetLogLevel, file)); LogManager.Configuration = conf; }
Databaseはちょっと変わり種でDatabaseParameterInfoのインスタンスにLayoutを設定しないといけません。
public static void WriteLogToSqlDatabaseInit(string connectionString, LogLevel targetLogLevel) { var conf = LogManager.Configuration; var dbtarget = new DatabaseTarget(); dbtarget.ConnectionString = connectionString; dbtarget.Name = "dbtarget"; dbtarget.DBProvider = "System.Data.SqlClient"; dbtarget.CommandText = "Insert Into LoggingTable(" + "Logged," + ") values (" + "@logged," + ")"; var loggedParam = new DatabaseParameterInfo(); loggedParam.Name = "@logged"; loggedParam.Layout = "${date}"; dbtarget.Parameters.Add(loggedParam); conf.AddTarget(dbtarget); conf.LoggingRules.Add(new LoggingRule("*", targetLogLevel, dbtarget)); LogManager.Configuration = conf; }
外部からNLogの設定を行う!
と、いうわけでソースコード上でNLogの設定が十二分に行えることがわかりました。
あとは、ASP.net WebAPIなどのappsettings.jsonなどに適当な設定を作ってあげればいいだけです。
適当に↓な感じでaapsettings.jsonを作って
{ "Logging": { "LogLevel": { "Default": "Warning" }, "OutputToLogFile": { "FilePath": "logfile.txt", "LogLevel": "Error" }, "OutputToDatabase": { "ConnectionString": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=Logging;Integrated Security=True;", "LogLevel": "Info" } }, "AllowedHosts": "*" }
Startup.cs
あたりで設定ファイルを読み込んでNlogを設定すればいい感じかなと思います。
private void NLogSettings() { Logging.LoggingSettings.ConsoleLogInit(); var fileName = this.Configuration["Logging:OutputToLogFile:FilePath"]; var logLevel = this.Configuration["Logging:OutputToLogFile:LogLevel"]; // NLogの設定を行う~~ }
これでWebAppsのアプリケーション設定への設定のみでログ出力先の挿げ替えなどが簡単に行えるようになりました。
終わりに
今回作成したモロモロのデモは下記リポジトリになります。
ASP.net WebAPIの ActionFilterAttribute
や ExceptionFilterAttribute
使ったり
EntityFrameworkの実行SQLをログ出力したりする実験コードも含んでたりします。
「簡単な」入力状態復帰機能をAngularのReactiveFormsで実装した話
はじめに
Angularは下記のバージョンでお送りします。
@angular/cli: 7.3.9
なにがしたかったか
- 認証にAzure ADを使用している関係で、定期的に(1時間立ち上げっぱなしで1回程度)ページがリフレッシュされる
- 入力内容が消えちゃうのもアレなので入力状態を保存しておいて復帰させたい。
- 巷の入力状態復帰ライブラリはCookieやlocalstorageに保存するものがほとんど
- じゃあライブラリ使わなくてもReactiveForms使ってたら余裕で実装できるかも?
というわけで実装してみよう…というあらましです。
行うこと
- ReactiveFormsの
valueChanges
イベントをサブスクライブします。 - ReactiveFormsはデータを構造体でもっているので、そのデータをJSONにしてlocalstorageに保存します。
- ComponentがInitializeされた段階でlocalstorageにデータが存在する場合は
patchValue
で入力されていたデータを復帰します。
以上。
極端な話、下記ソースコードだけで実現できるということですね。
(もちろん格納データの存在チェックやらは必要なのでこれ+もろもろは必要ですが!)
ngOnInit() { // 起動時にlocalstorageの値をFormsに反映 const stVal = JSON.parse(localStorage.getItem('hogehoge')); this.sampleInputFormGroup.patchValue(stVal); this.sampleInputFormGroup.valueChanges.subscribe(value => { // 変更内容をlocalstorageに保存 const valSt = JSON.stringify(value); localStorage.setItem('hogehoge', valSt) }); }
結果↓のGifのように動きます。
タブを閉じて再度開いても
入力状態が保持されている事がわかると思います。
まとめ
ReactiveFormsは構造体の状態で値の受け渡しができるので
ライブラリなしでも入力状態復帰処理は簡単に実装できますよ!ということがわかりました。
上の図で動いているソースのコードは下記になります。
Component - Service間をRxJSでつなげたりとか
ほんのちょっとだけ複雑になっています。
ごった煮のソースの一部で申し訳ないですが。。。 ><
KarmaやJestのカバレッジをAzureDevOpsパイプラインで収集してみた
昨日、Azure DevOps Tokyo, Japan 2nd impactに参加しました。
その時にAzure DevOps パイプラインでのカバレッジレポートの収集の話になり
自分が今使っているAngularのプロジェクトでも、カバレッジレポートが収集できるか試してみました。
現在、自分がAngularで行っているユニットテストは、KarmaとJestの2パターンあるので
その両方で試してみた結果となります。
はじめに
ちと古いですが、昔JestのテストとCIを組んだ構成を利用したので
Angular Cli:7.0.5で試した結果となります。
パイプラインでのカバレッジレポートのPublish
ユニットテストの結果出力同様、テストバレッジの結果出力も、専用のタスクがあるようです。
タスク名は「Publish Code Coverage Results」となっています。
パイプライン構築GUIで見てみると、下図のような設定画面となっているようです。
YAMLの設定については下記サイトに記載されています。
Publish Code Coverage Results task - Azure Pipelines | Microsoft Docs
ユニットテスト同様、結果出力されたXMLファイル指定するようです。
XMLのフォーマットとしてCobertura か JaCoCoのどちらかが指定されています。
ざっと調べてみたところ、JestもKarmaもCobertura フォーマットのXMLを吐けるようなので
Cobertura フォーマットのカバレッジレポートをパイプラインでPublishしようと思います。
Jest
Jest自身がCoberturaフォーマットのカバレッジレポートを出力する機能を持っているようなので必要最低限の変更で済みます。
AzureDevOps + Angular + Jestのテストパイプラインについては、以前の記事を参考にしてください
package.json
"test:watch": "jest --watch", - "test:ci": "jest --reporters=jest-junit", + "test:ci": "jest --reporters=jest-junit --coverage",
"reporters": [ "default", "jest-junit" ], + "coverageReporters": [ + "text", + "html", + "cobertura" + ]
上記の設定で、npm run test:ci
を実行すると、テスト実行時にcoverageディレクトリにカバレッジレポートが出力されます。
Karma
Karmaも簡単な変更でカバレッジレポートをcoberturaフォーマットで出力できるようになります。
angular.json
"karmaConfig": "src/karma.conf.js", + "codeCoverage": true, "styles": [ "./node_modules/@angular/material/prebuilt-themes/purple-green.css", "src/styles.scss"
karma.conf.js
coverageIstanbulReporter: { dir: require('path').join(__dirname, '../coverage'), - reports: ['html', 'lcovonly', 'text-summary'], + reports: ['html', 'lcovonly', 'text-summary', 'cobertura'], fixWebpackSourcePaths: true },
karma側も同様の構成でカバレッジの結果が出力されます。
Azure DevOpsパイプライン
Azure DevOps側に戻ってきました。
出力したカバレッジレポートのXMLとレポートHTMLを取得するタスクを作成します。
KarmaもJestも、同じ名前のディレクトリに同じ名前のファイルでXML出力されているので同様の設定となります。
タスクのyamlは下記の通りです。
yaml
- task: PublishCodeCoverageResults@1 displayName: 'Publish code coverage from $(System.DefaultWorkingDirectory)/**/cobertura-coverage.xml' inputs: codeCoverageTool: Cobertura summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/cobertura-coverage.xml' reportDirectory: '$(System.DefaultWorkingDirectory)/**/coverage'
- codeCoverageTool : 今回Coberturaフォーマットを使用したので
Cobertura
を指定します。 - summaryFileLocation : 出力されたXMLファイルを指定します。
- reportDirectory : カバレッジのHTMLレポートのディレクトリを指定できます。
結果
CIログのSummaryタブで全体の結果を確認できます。
CodeCoverageタブでは出力されたHTMLレポートが確認できます
デザインが統一されていないため、すこぶる見にくいです…
ダークテーマで見にくささらにドン。といった感じですね…
最後に
Angularに限らずKarmaやJestのテストフレームワークを使用している場合
コードカバレッジの結果をAzureDevOpsのCIでレポート出力するのはとても簡単だということが分かりました。
これでより良いユニットテストCIライフが送れそうですね!
AngularでQR/バーコードを使用するInputコントロールを作る
12/1 修正しました。
はじめに
今回のお話は、下記バージョンでお送りします
AngularCLI : 7.0.4
↓みたいなコントロールを作成していきます。
テキストボックスがあり
フォーカスが当たった際に、ソフトウェアキーボードではなくQRを読み込むカメラが起動し
カメラでQRが読み込めた場合
フォーカスが当たっていたテキストボックスに、QRから読み取った値を投入する。
といった動作です。
QR/バーコード読み込み
以前の記事でQRコードを読み取るために、@zxing/ngx-scanner
を使用しました。
今回は、そのライブラリからForkされた、@innotec/ngx-scanner
を使用します。
npm install @innotec/ngx-scanner --save
@zxing/ngx-scanner
の@Inputにはformats
が追加されており、CODE39等のバーコードのFormatを指定することで
バーコードのデータも読み込むことができるようになります。
Formatの指定は、@zxing/library
の Enumで管理されている、BarcodeFormat
の配列を使用します。
Selectorはzxingのngx-scannerと同様なので、下記のようにFormatを指定する部分のみが変わる感じです
<zxing-scanner #scanner [formats]="[BarcodeFormat.QR_CODE, BarcodeFormat.CODE_39]"> </zxing-scanner>
ngx-scannerの使い方は、以前書いた記事を参考にしていただければと思います。
AngularでQRする - はまったりひらめいたり…とか…
Angular Material BottomSheet
画面下からにゅっと飛び出てくるコントロールを作るために
AngularMaterialのBottomSheetコンポーネントを使用しました。
準備
まずは、Materialを使用するために、お決まりの
ng add @angular/material
を行っておきます。
@NgModuleでBottomSheeetのモジュールMatBottomSheetModule
をインポートしておきます。
親コンポーネントからの使用
constructorでMatBottomSheetのDIを行うことで、BottomSheetの処理が使用可能になります。
親コンポーネントから、BottomSheetのOpen()
を実行すればBottomSheetが表示されます。
その際、BottomSheet内に表示するComponentを指定することが可能です。
≪MatBottomSheet≫.open(SheetBodyComponent);
この時BottomSheetに表示されるComponentは、表示されるタイミングでインスタンス化されるようなので
LazyLoadするComponentの時同様、NgModuleのEntryComponentに加えてあげる必要があるようです。
@NgModule({ ... entryComponents: [ SheetBodyComponent ], ... }) export class AppModule { }
サービスの注入
QR/バーコードが読み込まれたタイミングで、親コンポーネントがその結果を引っ掛けたいです
ただ、BottomSheet内のComponentは、EntryComponentなので、@Output
あたりで引っ掛けるのも難しそうです。
なのでDIするClassを作成し、その中のSubjectなプロパティを介して
BottomSheet内Componentと、親Componentでデータのやり取りを行う方法をとろうと思います。
親コンポーネント
// BottomSheetをOpen const res = ≪MatBottomSheet≫.open(SheetBodyComponent); ≪DI Class≫.≪Subjectプロパティ≫.subscribe(x => { // QR/バーコードがScan出来た場合 // InputElementに対して取得したQR結果を突っ込む // ElementRefを使用しInputコントロールを取得する const con = <HTMLInputElement>≪ElementRef≫.nativeElement.querySelector('input'); con.value = x; // BottomSheetを閉じる res.dismiss(); });
BottomSheet内コンポーネント
handleQrCodeResult(resultString: string) { // QRが読み込めた時の処理。サービスのSubjectプロパティに値を流す ≪DI Class≫.scanSuccess.next(resultString); }
スクリプト内で特に指定しない限り、BottomSheetはEscキーなり、BottomSheet外をClickするなりしないと閉じないので
値が読み込めた段階で、bottomsheetのdismiss()
を使用して用がすんだら閉じてあげるのが良いかと思います。
bottomsheetのafterDismissed().subscribe()
で、BottomSheetが閉じた時を引っ掛けれるので
BottomSheet閉じた際に何か処理をしたい場合は、そいつを使うと楽にいろいろできそうです。
これで、親ComponentとBottomSheetのComponentでデータのやり取りが可能になりました。
結果
冒頭のGifの通り、QR/バーコードを使用したInputコントロールが作成できました。
おわりに
ソフトウェアキーボードみたいな、フォーカスあてると下からニュッと入力インターフェースが出てくるコントロールを作りたいという思いでBottomSheetを使用しました。
今回はQR/バーコードの読み取りで使用しましたが
Canvasあたりを使用すれば、手書きの入力コントロールも、OSのインターフェースっぽく表現できるかもしれませんね。
今回作成したものは、下記リポジトリで管理しています。
サンプルで作ったもののごった煮ですがご容赦ください。
バーコードとQRの生成は下記のサイトを使用しました。
バーコード
QR
Azure DevOpsとBlob StorageでClickOnceアプリケーションのCI/CDできるか「雑に」試してみた
はじめに
れがしぃなWindowsFormsなプロジェクトをAzure DevOps(ADO)でCI/CDできるか「雑に」試してみました。
exeをどこかに吐き出すだけでは面白くないので
Azure Blob Storage上にClickOnceアプリケーションをデリバリして
Web Apps上のリンクからそのアプリケーションを使用する。
みたいな形で構成していこうと思います。
「できるかな?」程度なので、超雑な構成になっています。
証明書周りやCORS周りなんかは、もうちょっと検証が必要と思います。。。
最終的に↓な感じで動きます。
Windows Formsプロジェクト
まずはWindowsFormsプロジェクトの作成です。
といっても、アプリケーション自体はそこまで重要ではないので
WindowsFormsの画面を表示させるだけの機能のものです。
アプリケーションの発行する際にClickeOnceの署名等も行うよう設定しておきます。証明書はVisualStudioで作成されるテスト証明書をそのまま使用します。
ADO CI/CDパイプライン
VisualStudioBuildタスク
ADOパイプラインのVisualStudioBuildタスクはデフォルトで、publishしてくれないので、タスクの内容を少しいじります
MSBuild:Arguments
に /target:publish
を指定するだけです。
PowerShellタスク
WinFormsのClickOnceで証明書を使用しているため、Buildを行う際にはマシンの証明書ストアに証明書がインストールされている必要があります。
PowerShellタスクを使用して、ビルドマシンに証明書をインストールしてあげます。
証明書ファイルはめっちゃ雑ですが
ソリューションに加えられたpfxファイルをADOにあげちゃってます
$pfxpath = 'pfxファイル' $password = '証明書パスワード' Add-Type -AssemblyName System.Security $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $cert.Import($pfxpath, $password, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]"PersistKeySet") $store = new-object system.security.cryptography.X509Certificates.X509Store -argumentlist "MY", CurrentUser $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]"ReadWrite") $store.Add($cert) $store.Close()
Azure File Copyタスク
ClickOnceアプリケーションは bin
の中に生成されるので
binディレクトリの中のファイルをFile CopyタスクでBlobストレージにアップロードします。
基本的にAzureのBlob Storageとリンクされます。なので迷わず設定できます。
結果
指定したコンテナに.application
他生成されたファイルがコピーされました。
Blob Storage他の雑な設定変更
ここからかなり雑です。
アセンブリの設定変更
オレオレ以前な証明書を使用しているので、*.application
にアクセスしてもファイルの起動が行なえません。
Let'sやらOpenSSLを使用してあげれば回避できるとは思うのですが
今回は、コンピューター\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\Security\TrustManager\PromptingLevel
の設定をすべてenabled
に変更して回避しました。
BlobStorageのアクセスポリシー変更
当初、SASトークン付きのURLでapplication
ファイルにアクセスしていたのですが
アプリケーションのインストールを行う際、当然 .manifest
などの他のファイルもBlobStorage経由で取得しようとします。
しかし、アプリケーションのインストール時は、インストーラでSASトークン付きのURLに対してアクセスしてくれないため、404が発生し、インストール時にエラーとなってしまいます。
BlobStorageでCORSを設定してみたのですが、そもそもローカルにインストールされたインストーラからのアクセスなので、CORSも効かない…
ので、アクセスポリシーをユッルユルに設定しアクセスできるようにしました。
雑に設定した結果
.application
へのLinkを貼っただけのHtmlをアップし動作させてみました。
結果は記事の冒頭に貼った通りの結果でClickOnceのおなじみの動きとなっています。
おわりに
BlobStorageにアップしたClickOnceアプリケーションは使用できそうです。
ただ、さすがにAnonymousで制限なくアクセス可能。という状態を避けたい場合はもうすこし考慮が必要かもしれません。
アプリケーションへのエントリがWebからのみ。ということであれば
Web画面のCI/CDパイプラインでアプリケーションを混入した状態で、WebAppsにデプロイしちゃったほうが良いかもしれないですね。
Azure DevOpsでAngularのJestテストのCIをまわせるか試してみた
はじめに
Angularは下記Verisonでお届けします。
- AngularCli:7.0.3
先日の、bitbank LT NightでみたJestがとても良い感じで使ってみたくなったので
現在使用しているCI環境のAzure DevOps(以降ADOと呼びます)で使用できるか確認してみました。
Azure DevOps
お仕事で使用していますが、Publicなプロジェクトでも使用できます。
Publicなプロジェクトの場合(厳密にはOSSプロジェクトとのことですが)、ビルド時間を無制限に回せるようです。
Azure DevOps のご紹介 – Cloud and Server Product Japan Blog
WebからWindowsアプリ、Andorid/iOSもビルド可能となかなか最強味が強い環境です。
OneDriveみたいに、無制限→制限!のような未来を辿らなければいいと願っています。
Angularの下準備
まずはAngularでJestのテストができるようにします。
下記を参考にしました。
ひとまず、ng new
したプレーンな環境から作成しました。
上記の記事に記載されている通りの変更を行います。
- パッケージのインストール
- jestテストするためのスクリプトをpackage.jsonに追加
- jestの設定ファイルの
jest.ts
をsrc
ディレクトリに配置 tsconfig.spec.json
の変更
あっさりとJestでテストが可能なところまで持っていくことができました。
結果レポートの出力
前の記事の内容の通り、ADOはjUnitのXMLを食わせばレポート出力してくれるので
jestからjUnitのレポートを出力できるようにします。
パッケージのインストール
jUnit出力に使用するパッケージをインストールします。
npm install --save-dev jest-junit
レポート出力の設定
Jestコマンドでレポート出力されるよう、package.json
の設定を変更していきます。
"jest": { ... "reporters": [ "default", "jest-junit" ] }
default
が先程行ったコマンドラインで表示されるテスト
jest-junit
がjUnitのXML形式で出力されるテストの設定です。
今回は、jest-junitのオプションに特に指定をしないので
rootディレクトリに「junit.xml」という名前で結果ファイルが出力されます。
テストコマンドも少し変更します。
今回の変更でテストレポートが複数パターンになったので
テスト内容によってどっちのレポートを使用するか指定しておきます。
package.jsonのスクリプトを下記のように変更しました。
"scripts": { ... "test": "jest --reporters=default", "test:ci": "jest --reporters=jest-junit", ... }
スクリプトコマンドの通り、npm run test:ci
でXMLが出力されます。
CIの構築
今回はGitHubリポジトリから、ソースを引っ張ってきてADOでCIします。
せっかくなので、Public環境のADOを使用しようと思います。
ADOの設定
GitHubのリポジトリからソースを引っ張ってくるパイプラインを作ります。
NewPipelineでGitHubを選択するだけ。簡単ですね。
テンプレートはどうせあとからいじるので、Blankなものを選択します
パイプラインを作成したら、ソースのリポジトリのルートディレクトリに
パイプラインの設定ファイルazure-pipelines.yml
が追加されています。
パイプラインをYamlで作成
パイプラインができたら、Buildの設定を作っていきます。
ADOのCIは、デフォルトではルートディレクトリにある、azure-pipelines.yml
の設定を参照し、CIのパイプラインが実行されます。
今回は、下記の感じで構成しました。
ルートディレクトリ配下にAngularのプロジェクトファイルがあるのでちと変則的ですが…
resources: - repo: self queue: name: Hosted VS2017 demands: npm npmインストール steps: - task: Npm@1 displayName: 'npm install' inputs: workingDir: AngularWithJest verbose: false npmテスト実行。CI用のテストを実行する。 - task: Npm@1 displayName: 'npm run test' inputs: command: custom workingDir: AngularWithJest verbose: false customCommand: 'run test:ci' 出力されたXMLファイルをテスト結果として取得する - task: PublishTestResults@2 displayName: 'Publish Test Results **/junit.xml' inputs: testResultsFiles: '**/junit.xml' condition: always() buildする。 - task: Npm@1 displayName: 'npm build' inputs: command: custom workingDir: AngularWithJest verbose: false customCommand: 'run prod-build'
ADOのyamlについては、下記サイトが参考になります。
YAML schema - Azure Pipelines | Microsoft Docs
結果
あえて失敗するテストを混入した状態でCIを回しました。
下記の通りきちんとエラーの内容が出力されています。
エラーを修正し、再度CIを回すと、きちんと反映されていることが確認できます
最後に
そもそもJest使用できるかな?程度のものなので、まだまだ検証することは多いかなと思います。
Jestは全然触っていないので、これからいろいろ覚えたい感じです。
さて、今回作成したソースと環境は下記になります。
Publicな環境でAzure DevOpsプロジェクト作成したのでテスト結果も見る事が可能です。
Azure DevOps: angularxstudy-ci
(僕の失敗の軌跡も見ることができるので少し恥ずいですが…)
AngularでQRする
はじめに
この記事は、下記のVersionでお送りします。
- Angular CLI : 7.0.3
どんな風に動作する?
こんな感じです。ちょっと見えづらいですが
一番下部で数字をカウントしているのがQRコードの読み取り結果です。
QRは2秒毎に0からカウントアップしていき、秒数をQRコードに変換しています。
QRコードの読み取りは早い方ではないでしょうか?
AngularでQRコードを読む
使用するライブラリ
QRコードを読むライブラリとしては、ネイティブではZxingが有名だと思います。
Angular用のZxingライブラリのngx-scanner
が開発されいますので
今回はそれを使用しようと思います。
注意
今、iOS12でQRを読み込んでくれないバグが存在するようです。
が、上のGifの通り動作していますね。
Angular6 + ngx-scannerの食い合わせが悪いのかもしれません。
(今回、Angularはv7を使いました)
次のリリースで解決するとアナウンスはされていますが、使用する際は注意が必要です。
IOS12 iphone/ipad · Issue #140 · zxing-js/ngx-scanner · GitHub
ngx-scannerの事始め
QRコードの読み取り機能自体は、非常に簡単に使用することができます。
npm i @zxing/ngx-scanner --save
して
Angularでは恒例の、ngModuleでインストールしたライブラリを読み込んでやってから
Htmlテンプレートで<zxing-scanner></zxing-scanner>
だけで使用できます。
ただし、Webカメラを使用する必要があるため
それを使用できるようにするまでで、ひと手間必要です。
デバイスで使用できるカメラを取得する
zxing-scanner
コンポーネントで使用できるカメラを探してくれます。
結果は、コンポーネントの camerasFound
ファンクションに
Obserbableで返却されます。
<zxingcomponent>.camerasFound.subscrive( devices => { hogehoge } )
で
引っ掛けて使用できるカメラデバイスを把握し
使用するカメラを選択する必要があります。
使用するカメラをコンポーネントの device
プロパティに食わせて
使用できる状態にする必要があります。
簡単に書くと下記な感じでしょうか?
<zxingcomponent>.camerasFound.subscribe((devices: MediaDeviceInfo[]) => { <zxingcomponent>.device = <zxingcomponent>.getDeviceById(devices["index?"].deviceId); });
ただ、カメラデバイスを見つけた時のObservableのみでdeviceを設定すると
好きなカメラに変更できないので
<zxingcomponent>.device
に食わせる値は変数にして
取得した devices
を保持して変更できるようにしておいたほうが良いです。
プロパティに使用するカメラの情報を食わせると
カメラを使用してQRを読み込んでくれるようになります。簡単ですね。
読み取り結果を取得する
Scanした結果は、Zxingコンポーネントの 'scanSuccess' ファンクションに
Observableで返却されます。
<zxingcomponent>.scanSuccess().subscribe(result: string => { })
で
結果を引っ掛けるだけでOKです。
camerasFound
も scanSuccess
もEventEmitterで結果が返却されているようなので
<zxing-scanner (camerasFound)="hogehoge()" (scanSuccess)="fugafuga()" >...
としてもいいと思います。これも非常に簡単ですね。
AngularでQRコードを生成する
使用するライブラリ
ngx-scannerで紹介されていた ngx-kjua
を使用します。
ngx-kjuaことはじめ
npm install ngx-kjua --save
して、同様にngModuleでライブラリを読み込んでから
Htmlテンプレートで<ngx-kjua></ngx-kjua>
で使用できます。
カメラ等のデバイスを使用しないため、特に前段階の準備をすることなく使用できます。
QRコードにしたい文字列かimageをコンポーネントのプロパティに下の感じで指定するだけで
QRコードが生成されます。超楽です。
<ngx-kjua [text]="'qrにしたい文字列'"></ngx-kjua>
さいごに
QRコードを用いたアプリケーションを比較的容易に作成することができます。
いろいろと利用できる範囲も広いですし、楽しい使い方もできると思います。
今回作成したWebApplicationは、下記レポジトリで管理してます。
Angularの勉強で使用したソースのごった煮ですが、ご容赦ください。