XamarinでUtf8Jsonを使おうとしてドはまりした話
最強Jsonシリアライザと噂のUtf8JsonをXamarinで使用しようとしてドはまりした話です。
公式のGithubは↓です。使用の仕方からすごくわかりやすく記述されています!
neue cc - Utf8Json - C#最速のJSONシリアライザ(for .NET Standard 2.0, Unity)
はまった原因としては。。。うん。まぁ環境構築やらで自分のやり方が悪いだけな気がします。。。
新規プロジェクトの作成から
ひとまずUtf8JSonは.netframework4.5からってことのようなので
.netframework4.5.2、Xamarin.Forms + PCLの上図みたいな構成で
新規にプロジェクトを作ってみました。
Utf8Jsonは公式GithubのREADMEどおりに、NuGetからパッケージインストールしてみます。
あーはん?
んー。Dependencyの子たちをInstallしてみようとしてもうまくいかない。。
.netframeworkのPCLのプロファイル構成を111とかに変更したり
.netframework4.5.2ではなく、4.5で新規にプロジェクトを作り直したり
VisualStudio for macで作ったりしてもダメだったので
.netstandard2.0のPCLにする方法で手を打ってみます。
.netstandard2.0のPCL構成に変更
とおもったけどデフォルトで.netstandard2.0なPCLの構成はつくれないのかな?
nuitsさんのこちらの記事を参考に、.netstandardなPCLを作成してみました。
上記の通り.netstandard、PCLライブラリもできて
エミュレータ上で実行確認できたので、本命のUtf8JsonをInstallしてみます!
うひょー!
Utf8Jsonうごくかためしてみる
Utf8Jsonの依存先のCLが、内部を実装してないと意味がないので動作するか試してみます。
確認につかったソースは公式のGithubのREADMEそのまんまです。
いぇあ!うごきました!
今回、XamarinFormsのプロジェクトに直接突っ込もうとしてドはまりしたわけだけど
実際の運用を考えるとUtf8Jsonを使用するような処理を切り出して
.netstandardのプロジェクトを別個作成することにはなると思う。
エンプラ脳でAngularのReactiveFormsを使ってみる
AngularのReactiveFormsは素敵なFormModuleだと思います。
自分も実際の作業の際には非常にお世話になりました。
ReactiveFormsについて
https://angular.io/docs/ts/latest/guide/reactive-forms.html
https://angular.io/docs/ts/latest/cookbook/form-validation.html
上記のAngularの公式サイトが大変参考になります。
基本のキは、上記サイトで学習できるので、エンプラ脳でReactiveFormsの利用方法を考えてみようと思います。
記事作成当時のAngularはV4です。
あと、これベストプラクティスかどうかはかなり怪しいので、色々ご意見いただけるとありがたいです。
Formでほしい機能を考える
さて、エンプラな頭で考えたとき、WebApplicationは同じような機能の複数の入力Formを持つかとおもいます。
入力Formは複数あれど、それぞれの画面で共通してほしい機能は存在するはずです。
さくっと考えて下記な感じでしょうか。
- Validarionエラーチェック
- エラーメッセージ
- ページ遷移時の挙動
- データ確定処理
同一の機能であれば、これらを共通のロジックでまとめて作りたい!
で、複数のComponentでまとめて使いたい!
ということで、作ってみようと思います。
結果、下図のような動きになります。色々サボってるので動きがちょいアレですが…
Validartionエラーチェック
これは、Angularの公式リファレンスにかかれているとおりの機能ですね。
ただ、各Componentで共通した機能として作りたいので、ReactiveFormsの諸々の処理を実装したBaseClassを作成します。
各ComponentでBaseClassをExtendsしてValidationの処理を書かなくていい感じに仕上げます。
また、Validationの設定を全部ComponentClassの中に書いていくのも邪魔くさいので
ValidationのSetting部分を切り出します。
作成するComponentでBaseComponentをExtendsして、上記で作成したValidarionのセッティングを読み込みます。
BaseComponentで、ValidationCheckに必要な作業をほぼ行っているので
実際のComponentに記述する量はガクッと減るかと思います。
getterでValidationSettingのコントロール名を返しているのは、ComponentのHtml内で楽に使用するためです。
HTMLは下記のような作りになっています。
地味に、AngularMaterialを使用して実装しています。
gistf9b185b48afceca9c50a04637a200300
formControlのNameの定義部分が[formControlName]となっているのが地味な味噌ですね。
エラーメッセージを格納しているformErros等の指定も、上記のようにしています。
ValidationSettingで設定しているCONSTのキーワード値を変更すると、関連項目のすべてに適用されるため
「DBの項目名称と一致してなかったテヘペロ」って場合も、最小限の変更で適切な箇所に変更を波及されます。
エラーメッセージ
エラーメッセージについては、
「必須ですよ」とか「文字列Overですよ」とか一般的なエラー内容は集約して管理したいので
エラーメッセージ生成Classを作成しました。
Static宣言してnewなしで使えるようにしています。
ページ遷移時の処理
入力中にページ遷移する場合、「いいの?」ってダイアログ出したい時があります。
そんな場合は、RouterのCanDeactivateを使用するのが良いですね。
下記の感じで作成しました。
CanDeactivateを使用する際にGenerics
その際、BaseComponentを継承して作成されたComponentと指定することで
Activate判断処理において、Component内の処理を呼び出せるようにします。
Componentの「canDeActivateInputPage」処理では、独自のダイアログをだすなり
何かの条件のときのみ確認するなり、よしなに処理を実装します。
今回はBaseComponentに処理を記述しましたが、継承先のComponentごとに実装をバラすこともできます。
Routerでは下記のように設定し、ページ遷移時に上記で作成したGuard処理が実行されるようにします。
データ確定時の処理
初っ端開いた状態だと、formはCleanな状態です。
Submitが走るとエラー状態にはなるものの
ValueChangeイベントが走らないため、FormsErrorsにエラー内容が格納されません。
なので、内部の全項目をDirty状態にして、ValidationCheckをあえて走らせる処理を実装します。
上記BaseComponentの↓の実装部分ですね。
allControlReCheck() { for (const field in this.formErrors) { const control = this.inputForm.controls[field]; control.markAsDirty(); this.onValueChange(); } }
あとは複製…
ValidationSettingとHtmlとComponentについては
画面に設定する項目に関するものだけを変更すれば、新しい画面が比較的ラクに作れるようになります。
最後に
今回作成したソースは下記リポジトリで管理しています。
AngularでCSVをAPIからDLするときに色々したお話
業務用のアプリケーション作ってるときに大概あるのがCSV出力ですが
WEBでCSV出力するときに、ちょいとはまったのでメモがてらに記事投稿します。
記事投稿時のAngularはV4です。
「IEで」下図のような感じで動くのを作ります
エクスポートしたCSVどうやってWEBで受け取るの?
一番単純な方法はAPIのURLを叩くのみですね。
window.location.href = "CSVを出力するAPIのURL";
CSVのレスポンスがあれば勝手にDLが始まります。
ただ、Chromeとかだと問題ないのですが
IEとかEdgeとかだと、utf-8のFormatでDLしようとしやがるので
場合によっては(shift-jisのファイルとか…)文字化けします。
こんな感じで…
あと、上記の方法だとビジネスロジックのエラー発生時にハンドリングしづらいです。
対策
受け取ったCSVデータからBLOBオブジェクトを生成
そいつに名前をつけてやる形で日本語名称の文字化けを解消します。
TypeScriptのAPIの受け口は下記のように作ります。
参考
readyStateが完了したとき、どのような状態で返却されたかによってresponseTypeを決定します。
(BLOBのままだとresponseTextでエラー吐いて使えないですからね)
WebAPI側では、ビジネスロジックエラーが発生した場合、InternalServerErrorのステータスで返却しています。
BLOB化したあとはCSVファイルとしてDLさせます。
ただ、IE系列とそれ以外とでロジックがちがうので下記のような感じなります。
最後に
今回作成したソースは下記リポジトリで管理しています。
Azureを使ってサクッと動画共有サービスを作る
YouTube等の外部Serviceを使用してもいいですが
Privateな環境で動画のアップロードをしたい場合があります
(業務利用ぐらいしか思いつきませんが…)
AzureのMediaService等を使っても良いかもしれませんが
同じくAzureのBlobStorageServiceを使用し、AzureのSDKを利用すれば
手っ取り早くプライベートな環境でビデオのアップロード&視聴が可能となります。
Angular+ASP.netで動画ファイルのアップロードと
視聴ページの作成を行ってみたいと思います
Azureの設定
CORSの設定
CORS(クロスオリジンリソース共有)を設定します。
Storageコンテナにアクセスするため、クロスドメインでアクセスできるように設定を行います。
参考にしたサイトでは、スクリプトで設定の変更を行っていますが
AzureのPortal上からも変更できるようです。
ポータルでCORSの設定を行う
1.リソースグルプでストレージアカウントを選択
2.ストレージアカウントの設定から「CORS」を選択
3.CORSの設定がないと思うので、「追加」を選択
4.上記の参考URLの内容をもとに、CORSの設定を行う
オブジェクトのAPIへのアップロード
前準備
ASP.Netはアップロードファイルの上限がデフォルト4MBとなっているので
受付可能なファイルサイズを拡張して上げる必要があります。
web.config
<system.web> <authentication mode="None" /> <compilation debug="true" targetFramework="4.5.2" /> <!--ファイルサイズの上限を変更しておく --> <httpRuntime targetFramework="4.5.2" maxRequestLength="102400" /> </system.web>
Webページからのファイルのアップロード
WebAPIへのアップロード
inputタグの[type=file accept=‘video/*’]であれば、取得対象が動画ファイルとなります。
(change)でファイル変更時のイベントを補足し、WebAPIにファイルを送る処理を実装します。
今回は横着かまして、Change即WebAPIへって感じの処理ですが
もちろん(change)でオブジェクト退避させ
Submit等のイベントを起点にAPIへおくるのが定石ですね。
<input type='file' accept='video/*' (change)="onChangeInput($event)" />
// Component private onChangeInput(el: any) { // イベントで変更されたValue=ファイルオブジェクトを取得 let file = el.target.files[0]; let formData = new FormData(); formData.append('uploadFile', file, file.name); this._webapi.putUploadFile(formData).subscribe(data => { console.log(data); }); } //---------------------------------------------------------- //webapiに送る処理 putUploadFile(formData: FormData): Observable<any> { return this.postFileData<any>("api/FileOperation", formData); }
WebApiではFormデータを送信する
//httpのPostリクエストでファイルを送信 private postFileData<T>(url: string, sendData: FormData) { return this.http .post(url, sendData, <headersContent>) .map(res => res.json()) .catch(error => { alert(error); return Observable.throw(error) }); }
WebAPIからAzureにBlobデータを登録する
POSTデータからファイルオブジェクトの取得
WebAPIではPOSTされたデータからファイル情報等を抜き出します。
public async Task<HttpResponseMessage> Post() { var response = new HttpResponseMessage(); var httpRequest = HttpContext.Current.Request; var mediaType = Request.Content.Headers.ContentType.MediaType; if (httpRequest.Files.Count > 0) { foreach (string file in httpRequest.Files) { var postedFile = httpRequest.Files[file]; /*→Azureの登録処理へ→*/ } } return response; }
コンテナにオブジェクトの登録
まずはAzureSDKを使用して、登録対象ストレージを選択(なければ作成)します。
var credentials = new StorageCredentials(<ACCOUNT_NAME>, <ACCOUNT_KEY>); var storageAccount = new CloudStorageAccount(credentials, true); var blobClient = storageAccount.CreateCloudBlobClient(); container = blobClient.GetContainerReference(<CONTAINER_NAME>); container.CreateIfNotExists();
AzureのAPIはファイルはByte引数となりますので
httpRequestのFileのStream型をByte型に変換してAzureのAPIに渡します。
[GetBlockBlobReference]でAzureにUpload出来る形にした後
[UploadFromByteArrayAsync]でAzureにアップロードします。
var sendByteData = //file.InputStreamをByte[]変換; //Blobにアップロードする対象のファイルを決定 var blob = container.GetBlockBlobReference(FILE_NAME); //メディアのタイプを決定 blob.Properties.ContentType = mediaType; //Blobにアップロード await blob.UploadFromByteArrayAsync(sendByteData, 0, sendByteData.Length);
SASを付与したURLの生成
BlobへのアクセスはShared Access Signature (SAS) で作成したURLを使用してアクセスします。
その為、作成したデータにアクセスするためのアドレスを生成します。
//コンテナ内のファイルを指定 var blob = container.GetBlockBlobReference(FILE_NAME); //SASアドレスの作成 var sas = blob.GetSharedAccessSignature(new SharedAccessBlobPolicy() { //読取りのみ Permissions = SharedAccessBlobPermissions.Read, //1時間だけアクセス可能 SharedAccessExpiryTime = DateTime.UtcNow.AddHours(1) }); //BlobのURIとマージしてURLを生成 var Url = string.Format("{0}{1}", blob.Uri, sas);
VideoのSrcにバインドしVideoを見れるようにする
JSONでURLを返却したら、VideoのsourceにURLをバインドします。
コストについて
日和って短い時間の動画しか上げていませんが
1週間ほど放置してもTOTALで1円以下ですんでいます。
Webサービスの一環として、かんたんでPrivateな動画共有サービスとしては導入しやすいのかなと思います
jQueyプラグインをAngular v2で使いたい(FullCalendar)
Angularを使用するようになって、jQuery自体は殆ど使用しなくなりました。
Componentベースでアプリを作成したときに
jQueryの処理が全体に波及するので使いにくかったんですね。
(特に同じ部品のComonentを親Componentで何度も使用しているときとか。)
ただ。jQueryの覇権時代が長いだけに
それを使いたいなー。という思いもあるわけです。
なので、今回は、jQueryのプラグインをAngularで使用してみたいと思います。
How to include JQuery plugins in Angular 2 running via webpack
といっても、上記の記事の焼き直しみたいな感じになっていますが…
今回は手っ取り早くangular-cliを使用して、作ってみようと思います。
angular-cliを使用することで
比較的手軽にangularの開発&Build環境を構築することが可能です。
angular-cliの使い方は今回の本筋ではないので下記を参考に。
npmでパッケージをダウンロード
まずは、モノがないと始まらないので
jQueryと今回使用したいFullCalendarをnpmでダウンロードします。
npm install jquery npm install fullcalendar
型定義ファイル+αをダウンロード
jQueryとFullCalendarは型定義ファイルが提供されているので
下記の2つの型定義ファイルをダウンロードします。
npm install @types/jquery npm install @types/fullcalendar
また、FullCalendarの型定義ファイル上で
日付等の指定にmoment.jsの型が指定されているので
moment.jsと、その型定義ファイル @types/momentもダウンロードします。
npm install moment npm install @types/moment
angular-cli.json
Angular-cliを使用している場合
外部コンポーネント等のCSSやJavascriptを使用しやすいです。
angular-cli.jsonに外部JSやCSSを読み込むオプションが存在するためです。
今回、FullCalendarを使用するため、FullCalendarのCSSを別に読み込みます。
"styles": [ "../node_modules/fullcalendar/dist/fullcalendar.css" ]
FullCalendarの実装
参考サイトの通り、FullCalendarを使用するComponentを分離して作成します。
Htmlにng-contentを指定し、そこにjQueryでFullCalendarを注入します。
HTML
<ng-content></ng-content>
Component上のHTMLにはng-contentしかないので
this.elementRef.nativeElementのみで指定できますね。
型定義ファイルを使用することで型検証されるようになるため
どのような値をつっこめば良いのかわかりやすくなります。ビバ型。
TypeScript
this.calendarElement = jQuery(this.elementRef.nativeElement); this.calendarElement.fullCalendar({ editable: true, defaultView: 'agendaWeek', selectable: true, selectHelper: true });
仕上げ
あとは上記で作成したComponentを使用し、[ng serve]で実行して動作確認です。
表示するだけでは味気ないので、下のように書き換えてみました。
this.calendarElement = jQuery(this.elementRef.nativeElement); this.calendarElement.fullCalendar({ allDayText: '終日', editable: true, defaultView: 'agendaWeek', selectable: true, selectHelper: true, slotDuration: moment.duration(15, 'minutes'), slotLabelFormat : 'H:mm', buttonText: { today: '今日' }, monthNames: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], dayNames: ['日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'], dayNamesShort: ['日', '月', '火', '水', '木', '金', '土'], views: { month: { columnFormat: 'ddd' }, week: { columnFormat: 'D[(]ddd[)]' }, day: { columnFormat: 'D[(]ddd[)]' } }, select: this.onSelectFunction, eventDragStop: this.onDropFunction, eventResize: this.onReSizeFunction, eventRender: this.addEventRender });
/*FullCalendarで定義されていないイベントを付与する(ダブルクリック)*/ private addEventRender = function(event: FC.EventObject, element: any){ element.bind('dblclick', () => { alert('onDoubleClickEbent'); console.log(event); }); } /*カレンダーセレクト時*/ private onSelectFunction = function(start, end){ let eventTitle = prompt('予定の名称を入力せよ!!'); let eventData: FC.EventObject = { start: start, end: end, title: eventTitle }; this.calendarElement.fullCalendar('renderEvent', eventData, true); this.calendarElement.fullCalendar('unselect'); }.bind(this); /*イベントオブジェクト移動時*/ private onDropFunction = function(event: FC.EventObject){ console.log('Drop!'); console.log(event); }.bind(this); /*イベントオブジェクトサイズ変更時*/ private onReSizeFunction = function(event: FC.EventObject){ console.log('ReSize!'); console.log(event); }.bind(this);
日付の表示Formatを変更し、各イベントの処理を実装します。
イベントの引数はFunctionを指定しますが
その場合、calendarElementのobjectが[this]となります。
Angularを使用するうえで色々と使いづらいので、Functionにthisをbindして
FullCalendarを宣言しているClassのオブジェクトを[this]としています。
そうすることで、Angularの機能の諸々を使用しやすいようにしています。
動作させてみる
Console内部にイベントオブジェクトを表記するようにしています。
moment型のデータ等が問題なく取得できていることが確認できるかと思います。
最後に
一応今回のソースは下記に上げてあります。
Angular2Study/UseFullCalender at master · Takas0522/Angular2Study · GitHub
ASP.net MVC4 + Angular v2 + webpack
以前にASP.Net4+Angularで記事を書いたことがありましたが
当時、R.C版だったこともあるので、現在のVer.で作り直してみようと思います。
といっても前回より環境や情報が整ったこともあり、そんなに難しい内容にはならないと思います。
ただ割と無茶な作り方をしているので、素直にCoreかMVC5を使用することをオススメします。
ASP.net MVC4 + Angular v2について、公式にガイドが出ています。
ただ、EmptyなプロジェクトにAngularを乗っけるものなので簡易気味です。
簡易な状態でとりあえず動かしてみたい!ということであれば
公式のガイド通りにやったほうが良いとおもいます。
前半は、AngularのWebpackのIntroductionの通りに進みます
その後、ASP.netMVC4で使用できるよう調整していきます。
注意
今回のものについては僕がとった方法となるので、絶対条件について記述しているものではありません。
Angularは「~2.4.0」を対象としています。Ver.が変わると、この方法でもエラーが発生することは十二分にありえます。
参考サイト
文中で出てきてますが、今回参考にしたサイトをまとめて掲載します。
Angularのソースを構築する
上記のAngularのWebpackのIntroductionの内容をすべて行います。
記事作成時点だとチュートリアルの内容は古かったようなので
Webpackを使用したAngularのBuild時点でエラーが発生した場合は、下記URLの内容を試してみましょう。
また、下記のようなエラーが発生する場合はnode.jsがv6.9.4以下の状態の可能性があります。
outputOptions.children = options.map(o => o.stats);
そして、VisualStudioのタスクランナーで上記のエラーが発生している場合は下記URLの対策を行います。
チュートリアルで行っている主たるところは下記の内容ですね。
それぞれの内容については今回言及することではないと思うので省きます。
TypeScript開発環境の構築:tsConfigの設定
Webpackビルド設定(Webpack.config)
Unitテストシステムの構築(karima.conf)
チュートリアルを行った上で、Angular単体でビルドがうまくいっているか確認してみましょう。
VisualStudioのBuildでななく、コンソールで「webpack」を実行し確認します。
VisualStudioの画面で「のみ」TypeScriptソースでエラーが出ているときは
AngularのBuild時点でエラーが発生していないが
VisualStudioのエラー一覧でエラーが発生している場合、VisualStudio側の構成に原因があることがあります。
AngularのBuild時はプロジェクトのnode_module内のTypeScriptを参照してくれますが
VisualStudioではnode_moduleの設定を見ずに、VisualStudioが持っているTypeScriptの設定で
エラー判断を行っていることがあるようです。
そんな場合は、下記のそれぞれを行うことで解消できる可能性があります。
TypeSript2.xのダウンロード
使用するTypeSCriptとVisualStudioのTypeScriptが一致していない可能性があります。
VisualStudioのTypeScriptExtensionをインストールしましょう。
Download TypeScript for Visual Studio 2015 - 日本語 from Official Microsoft Download Center
プロジェクトファイルのTypeScriptVerの修正
TypeScriptの旧Verが使用されている環境でプロジェクトを作成した場合
プロジェクトで使用されるTypeScriptVersionがプロジェクト内に残っている場合があります
.cproj内のTypeScriptVersionを変更します。
<TypeScriptToolsVersion>2.x</TypeScriptToolsVersion>
環境変数に残存するTypeSrript情報の削除
VisualStudioの古いTypeScriptバージョン情報が、環境変数に残っている可能性があります。
下記記事の内容をもとに、環境変数の情報を修正しましょう。
ASP.netで使うためのソースの修正
Webpackの修正
現在、バンドルされたファイルは[dist]ディレクトリに格納されています。
VisualStudioの初期配置のパス上には[dist]は存在しないのでちょいと使いづらいです。
[Scripts]ディレクトリに変更しましょう。
webpack.dev.js
output: { - path: helpers.root('dist'), + path: helpers.root('Scripts'), publicPath: 'http://localhost:8080/', filename: '[name].js', chunkFilename: '[id].chunk.js' }
ASP側のRouting設定の変更
クライアントはSPA構成で作成することになるので、ASP側のルーティング等は現状必要ありません。
また、Angularのルーティングで生成されたURLで404を吐かないようにする必要があります。
Web.configで404をが発生した場合、ベースページに飛ばすのも良いかもしれませんが
リダイレクトが発生しまくるので得策ではないかと思われます。
ASPのルーティングとうまく組み合わせて使えば、簡易なLazyLoadingとしても使えるような気がします
(Angular+WebPackでLazyLoadingする機能はありますが…)
ひとまず、ベースとなるページを残して、あとは潰してしまい、それに合わせてRoutingの設置を変更します。
RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); - routes.MapRoute( - name: "Default", - url: "{controller}/{action}/{id}", - defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } - ); + routes.MapRoute( + name: "Default", + url: "{*url}", + defaults: new { controller = "Home", action = "Index" } + ); }
BundleConfigの変更
バンドルして生成された3種のJavascriptファイルは、BundleConfigでBundleして出力します。
起点をindex.htmlではなくしたので、ComponenntのStylesに関しては、今回の場合は使用し辛いので cs CSSもComponentで取り込まず、外部から直接使用します。
app.component.ts
@Component({ selector: 'my-app', templateUrl: './app.component.html', - styles: ['./app.component.css'] })
なのでCSSもSCSS等でまとめて作っちゃうのがいいかもしれませんね。
今回はチュートリアルで作成したCSSをSCSSで作成し直し、Styles.scssで作り直し
生成されたStyles.cssをバンドルします。
public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new ScriptBundle("~/bundles/src").Include( "~/Scripts/polyfills.js", "~/Scripts/vendor.js", "~/Scripts/app.js" )); bundles.Add(new StyleBundle("~/public/css").Include( "~/public/css/styles.css")); }
_Layout.cshtmlの変更
_Layout.cshtmlの構成をAngularのindex.html同様の構成に変更してきます
<!DOCTYPE html> <html> <head> <base href="/"> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>@ViewBag.Title - Sample</title> @Styles.Render("~/public/css") </head> <body> <div class="container body-content"> @RenderBody() </div> @Scripts.Render("~/bundles/src") @RenderSection("scripts", required: false) </body> </html>
Home.cshtmlを変更
Angularの起点をHome.cshtmlに作成します。
html
<my-app>NOW LOADING...</my-app>
## App_Start系の変更
App_start等のIdentity等々を潰してまわります。
まぁ残しておいても良いですが。
Angularソースの変更
webconfigを使用した場合、相対ファイルパスで表示するimg等のオブジェクトデータは
Webconfigバンドル時によしなにしてScriptファイルにつっこまれます。
つまり、今回のようにASP.netのcshtmlに乗っける場合は非常に使いにくいです。
例えば下記のようにHTMLを記述してもAngularのBuild時点で存在しないとして怒られて終了します。
<img src = "Script/assets/hogehoge" />
なのでバインド変数を使用します。
app.component.ts
export class AppComponent { private angularPng: string = "public/images/angular.png"; }
app.component.html
<main> <h1>Hello from Angular App with Webpack</h1> <img [src]="angularPng"/> </main>
VisualStudioでデバッグしましょう
通りましたね?
Advanced
root配下に切ったディレクトリにWebAppを配置したばあい
Angularで設定するBASE_HREFを[/]で設定していたら
切ったディレクトリ内に配置していても、AngularのRoutingはRootから生成されます。
そうなった場合、ASP.netのAPIやimage等のObjectの使用に難が生じますので
BASE_HREFを動的に変更させる必要があります。
そしてそのHREFをAngularで取得すれば、API等とのやりとり等に使用できるようになります。
最後に
一応、今回作成したものは、下記に乗せています。
もくもく会でもくもくしたお話
Angular2ばっかりもアレなんで、下記のもくもく会に参加してXamarinばっかり考える時間を設けました。
今回はいうほどはまるポイントがなかったというか
クリティカルな参考サイトが多かったため、参考サイトの紹介程度です。
成果
↓動作結果↓
EnumデータをバインドするPicker
- 参考サイト
ListView表示用のEnumデータコンバータ
- 参考サイト
SQLiteを使用したViewModelベースデータの登録と削除と画面反映
- 参考サイト
他内容で勉強中に行き当たった興味深い参考サイト
AlertViewのカスタマイズ? stackoverflow.com
カスタムレンダラでジェスチャーのイベントを捉える