GitHub Pages でホスティングするための Blazor WebAssembly の Visual Studioテンプレートを作りました
Blazor WebassemblyがついにRC版になり、正式版のリリースまで秒読みとなりましたね!
Blazor Webassembly の静的サイトをGitHub Pagesでホストする
Blazor Webassembly の静的サイトをGitHub Pages でホストする場合、SPAのルーティング行うために少々小細工をする必要がありました。
下記の記事などを参考に、その対応を手作業で行っていたのですが、ちょっと面倒なのでVisual Studioのプロジェクトテンプレートにしてみました!
qiita.com
Blazor Webassemblyの公式テンプレートをベースに、上記記事に書いてあるような変更を加えただけのものですが、Github Actions の自動ビルド&デプロイの設定も含めています。
テンプレートからプロジェクトを作成して、GitHubにプッシュするだけでGitHub Pagesのプロジェクトサイトとして公開できてしまう超お手軽なテンプレートですので、ぜひ一度お試しください!
- Visual Studio Marketplace
LINE Botのリッチメニューを作成するVisual Studio拡張 「XAML Rich Menu Maker」をリリースしました
はじめに
以前このブログで紹介したLINE BOTのリッチメニューをXAMLでデザインするツールをVisual Studioの拡張機能としてリリースしました!
LINE Developer Community
ソースコードはGitHubの 「LINE Developer Community」というOrganization で公開しています。 github.com github.com
ここには他にも、 LINE BOTやClovaスキル等 LINE プラットフォームを利用したアプリケーションの開発に使えるC#( .Net Standard )のライブラリが多数収録されています。こちらも合わせてご活用ください!
- LINE Messaging API
- LINE Pay
- LINE Login
- Clova Extensions Kit
- LIFF (LINE Front-end Framework のBlazor用C#ラッパー)
※ なお、現在はC#のライブラリ・ツールがメインですが、他の言語・開発環境のリポジトリも随時追加して行く予定です。
「自分のライブラリ・ツール等も登録してほしい」という方も募集中です!
興味のある方はLINE Developer Communityまで!
インストール
Visual Studio Market Place からVSIXファイルをダウンロードしてインストールする場合
以下のサイトにアクセスして[Download]ボタンをクリックしてVSIXファイル(XRMMVsixProject.vsix)をダウンロードします。 marketplace.visualstudio.com
ダウンロードしたVSIXファイルをそのまま実行してください。(起動中のVisual Studioがある場合はいったん終了してください)
Visual Stdio 2019 の「拡張機能の管理」を利用してインストールする場合
Visual Studioのメニューバーで[拡張機能]-[拡張機能の管理]をクリックし、「Manage Extensions」ダイアログを開きます
ダイアログ右上の検索エリアに「XAML Rich Menu Maker」と入力して検索
検索結果に「XAML Rich Menu Maker」が表示されたら「Download」ボタンをクリックします
使い方
XAML Ritch Menu Makerプロジェクトを作成する
Visual Studio のメニューバーで[ファイル]-[新規作成]-[プロジェクト]をクリックし、「新しいプロジェクトの作成」ダイアログで「LINE Ritch Menu Maker」を選択して「次へ」をクリック
任意のプロジェクト名を入力して「作成」をクリックするとXAML Ritch Menu Makerのプロジェクトが作成されます。
- プロジェクトが作成されたら、メニュー[ビルド]-[ソリューションのビルド]で一度だけビルドを実行します。
BOTアカウントの設定を行う
リッチメニューを利用するBOTアカウントの設定を行います。
- ソリューションエクスプローラで「appsettings.json」をクリックして編集画面を開き、LINE Bot のチャネルアクセストークンを入力します。
- また「DebugUserId」には、LINE Developers の「チャネル基本設定」画面の「その他」「Your user ID」に記載されている自分のユーザーIDを設定します(こちらは必須ではないです)。
{ "AppSettings": { "ChannelAccessToken": "+CiR37Hw0xxxxxxxxxxxxxxxxx", "DebugUserId": "U28aa2xxxxxxxxxxxxxxxxx" } }
XAMLエディタでリッチメニューをデザインする
リッチメニュー定義ファイル(XAML)を作成する
- ソリューションエクスプローラで「RichMenuDefs」フォルダを右クリック
- 表示されるメニューで[追加 ▶] [新しい項目...]をクリック
- 新しい項目の追加ダイアログで「LINE Rich Menu Definition (XAML)」を選択、ファイル名を入力して「追加」
以下のXAMLファイルが作成されます。これを編集してリッチメニューのデザインを行います。
<local:RichMenuDefsControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:XamlRichMenuMaker;assembly=XamlRichMenuMaker" xmlns:system="clr-namespace:System;assembly=System.Runtime" mc:Ignorable="d" d:DesignHeight="1000" d:DesignWidth="2600"> <UserControl.Resources> <system:Double x:Key="RichMenuWidth">2500</system:Double> <system:Double x:Key="RichMenuShortHeight">843</system:Double> <system:Double x:Key="RichMenuNormalHeight">1686</system:Double> </UserControl.Resources> <Grid Width="{StaticResource RichMenuWidth}" Height="{StaticResource RichMenuShortHeight}" > <Grid x:Name="menu_body" Background="LightGray"> <local:RichMenuProperties.Settings> <local:RichMenuSettings Name="" ChatBarText="" Selected="True"/> </local:RichMenuProperties.Settings> <!-- Design your rich menu layout here. --> </Grid> </Grid> </local:RichMenuDefsControl>
リッチメニューの設定
リッチメニューの高さ
リッチメニューのサイズは一番外側のGridのWidth,Heightで指定されています。
ファイルを作成した段階では、Shortサイズの高さが指定されています。大きいサイズのリッチメニューを作成したい場合はHeightをRichMenuNormalHeightに変更してください。
<Grid Width="{StaticResource RichMenuWidth}" Height="{StaticResource RichMenuNormalHeight}" > </Grid>
リッチメニュー全体の設定を行う
リッチメニューの画像として保存されるのは、”x:Name=menu_body”とタグ付けされたGridコントロールです。 このGridに対して以下の値を設定します。
- Grid の Background プロパティにGridの背景色を指定します。
メニュー登録時の各種設定を添付プロパティRichMenuProperties.Settings で指定します。 指定する項目には以下があります。
- Name: リッチメニュー名
- ChatBarText: LINEのチャット画面下のメニューバーに表示されるテキスト
- Selected: デフォルトでリッチメニューを表示状態にする場合にTrueを指定
リッチメニューの外観をデザインする
リッチメニューの外観は Grid ”menu_body" の中にコントロールを配置することでデザインします。
ここからは作成したプロジェクトのRichMenuDefsフォルダに入っているSampleMenu.xmlを例に説明します。
まずGridで2つのボタン領域を決め、そこにImageコントロールでアイコン画像を、TextBlockでボタンのキャプションを設定します。
<!-- 列を2つ作り、1つ目と2つ目の幅の比を2:1に設定 --> <Grid.ColumnDefinitions> <ColumnDefinition Width="2*"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <!-- 1つ目のボタンの画像とキャプション --> <Image Source="../Resources/cat.png" VerticalAlignment="Top" Margin="0,150,0,0" Width="420" Height="420"/> <TextBlock Margin="0,0,0,80" VerticalAlignment="Bottom" HorizontalAlignment="Center" FontSize="80"> Hello! LINE BOT! </TextBlock> <!-- 2つ目のボタンの画像とキャプション --> <Image Grid.Column="1" Source="../Resources/web.png" VerticalAlignment="Top" Margin="236.333,180,237,0" Width="360" Height="360"/> <TextBlock Grid.Column="1" Margin="0,0,0,80" VerticalAlignment="Bottom" HorizontalAlignment="Center" FontSize="80">Web Site </TextBlock>
アクションエリアを設定する
次に、リッチメニューの中でボタンとして機能する領域(=アクションエリア)を定義します。 定義する項目は以下の2つです。
- Bounds: アクションエリアの座標
- Action: エリアをタップした際に動作するアクション
Boundsには、x:Name="area_{n}" (nには1~20の番号を指定)でタグ付けしたコントロールの座標をそのまま使用します。
サンプルの例では、ボタンの境界の表示も兼ねてRectangle コントロールを使用していますが、別のコントロールでも構いません。
領域をタップした際に動作するActionは 上記コントロールに添付プロパティRichMenuProperties.Actionを指定することで定義します。
<!-- Action Area 1 --> <Rectangle x:Name="area_1" Stroke="DarkGray" StrokeThickness="4"> <local:RichMenuProperties.Action> <local:RichMenuAction Type="Postback" Label="Hello!" Data="Hello!" Text="Hello! LINE BOT!"/> </local:RichMenuProperties.Action> </Rectangle>
Actionには次の4タイプが指定できます。
- Postback
- Message
- URI
- Datetimepicker
各アクションに必要な設定項目については以下をご参照ください。
アクションオブジェクト: Messaging API リファレンス
Messaging APIを用いてリッチメニューを作成する
XAMLでのデザインが完了したら、LINE Messaging APIを使用してリッチメニューを作成します。
[Ctrl]+[F5]キーを押してアプリケーションを実行します。
アプリケーションが起動すると、以下の様にXAMLでデザインしたリッチメニューの画像と、Messaging APIでLINE側に送信するJSONの内容が表示されます。
内容を確認してOKなら「Create Rich Menu」ボタンをクリックします。
これでリッチメニューの作成とアップロードの完了です!
作成・登録済みのリッチメニューを確認する
[Create Rich Menu]ボタンの右側にあるコンボボックスを開くと、XAMLファイルで定義したリッチメニュー名(XAMLファイル名)の下に既に登録済みのリッチメニューID(”richmenu-”で始まる文字列)が表示されます。
これらを選択することで、リッチメニューの内容(画像、JSON)を確認することができます。
また、選択したリッチメニューに対して以下操作が可能です。
C#のソースコードからPlant UMLのクラス図を生成するツール PlantUmlClassDiagramGenerator v1.2.0 をリリースしました
溜め込んでしまっていたPull Requestを幾つかマージしました。また、ターゲットを.NET Core 3.0 に変更しています。
以下からダウンロードしてお試いただけます。
.Net Core Global Tools
- PlantUmlClassDiabramGenerator v1.2.0 www.nuget.org
Visual Studio Code Extension
- C# to PlantUML marketplace.visualstudio.com
更新内容
主な変更は以下の通りです。
Null許容型のクラスメンバに対応しました。
以下のように?を付けたNullable型は変換できなかったのですが、変換できるようになりました。
[C#]
class ClassA { public int? PropA { get; set; } }
[PlantUML]
class ClassA { + PropA : int? }
All in One オプションを追加しました
フォルダ内のCSファイルを一括で変換した場合、include.puml ファイルに !include
で出力した全ファイルの参照を登録して全部のクラス図を一枚に収めることができるようになっています。
@startuml !include .\\ClassA.puml !include .\\ClassB.puml !include .\\ClassC.puml @enduml ...
しかし、環境によっては !include ディレクティブが利用できない場合があるため、パラメータに -allInOne
オプションを付けた場合は include.puml にファイルの参照ではなくファイルの中身をそのまま書き込まれるようになります。
@startuml class ClassA{ } class ClassB{ } class ClassC{ } @enduml
Blazorクラスライブラリ内で使用するアセット(JS,CSSファイル等)をWebアプリ側に配置するには
本記事は、Blazorで使えるLIFF(LINE Front-end Framework)のC#ライブラリを実装した際の実装メモです pierre3.hatenablog.com
Blazor用のクラスライブラリを作る
Blazor 用のクラスライブラリを作成する際、Microsoft.AspNetCore.Blazor.Templates の バージョン 3.0.0-preview7.19365.7 に入っていた「Blazor library」テンプレートを使用していました。
しかし、preview8以降このテンプレートは無くなっていて、現在は「Razorクラスライブラリ」テンプレートを使用するようです。
そこで、今回作成したライブラリも以下のドキュメントを参考に「Blazorクラスライブラリ」テンプレートに置き換えてみました。
docs.microsoft.com docs.microsoft.com
プロジェクトの構成的自体にあまり変わりは無かったのですが、以下の部分で問題がありました。
Razorクラスライブラリ側のアセットがWebアプリ配置先の「dist」フォルダに出力されない
テンプレートから作成したプロジェクトは以下のような構成になっています。
wwwroot に配置した JSやCSSのファイルが、参照元のWebアプリ(Blazor WebAssembly)側にコピーされて利用可能となる想定です。 しかし、Webアプリを実行してもライブラリ側のJSファイルが認識されませんでした。
Blazor WebAssemblyのプロジェクトをビルドすると「bin\(Debug | Release)\dist」配下にアプリの一式が配置されます。 ライブラリ側のアセットファイルもこの下に格納されると思ったのですが、入っていませんでした。
また、「発行...」でフォルダに配置し、配置先の「.\publish」フォルダを確認してみたところ
アプリ配置先の .\publish\{Webアプリのアセンブリ名}\dist
フォルダには配置されず、「publish」フォルダ直下に作成された「wwwroot」の中に格納されていました。
- publish
このあたりの正しい構成方法についてはもう少し調べてみたいですが、ひとまずは古いテンプレートの設定に戻して対処することとします。
ライブラリ側のコンテンツをdistフォルダに出力させる
Razorクラスライブラリで以下の修正を行います。
- ライブラリ側の「wwwroot」フォルダ名を「contents」に変更する
- ライブラリ側のプロジェクトファイル(.csproj)に以下のコードを追加する
<ItemGroup> <!-- .js/.css files will be referenced via <script>/<link> tags; other content files will just be included in the app's 'dist' directory without any tags referencing them --> <EmbeddedResource Include="content\**\*.js" LogicalName="blazor:js:%(RecursiveDir)%(Filename)%(Extension)" /> <EmbeddedResource Include="content\**\*.css" LogicalName="blazor:css:%(RecursiveDir)%(Filename)%(Extension)" /> <EmbeddedResource Include="content\**" Exclude="**\*.js;**\*.css" LogicalName="blazor:file:%(RecursiveDir)%(Filename)%(Extension)" /> </ItemGroup>
これでWebアプリ側の「dist」フォルダ内に出力されるようになります。
Blazor WebAssembly のJS相互運用で、引数にコールバック関数を受け取る関数を実行する方法について
本記事は、Blazorで使えるLIFF(LINE Front-end Framework)のC#ライブラリを実装した際の実装メモです pierre3.hatenablog.com
JavaScriptの関数をC#から実行する
Microsoft.JSInterop.IJSRuntime
インターフェースを利用します。
基本的には、JSRuntime.InvokeAsync
メソッドに実行したいJSの関数名を渡すだけでOKです。
関数名はグローバルスコープ(window)を基準とした名前です(window.liff.init()
の場合 liff.init
を渡す)
public async Task CloseWindowAsync() => await JSRuntime.InvokeAsync<object>("liff.closeWindow").ConfigureAwait(false);
引数がある場合
引数がある場合、引数と同じ名前のプロパティを持ったオブジェクトを渡します。 匿名オブジェクトで渡すのが簡単です。
public async Task OpenWindowAsync(string url, bool external) => await JSRuntime.InvokeAsync<object>("liff.openWindow", new { url, external }).ConfigureAwait(false);
戻り値がある場合
戻り値がある場合、ジェネリクスの型引数に指定すればその型で受け取ることができます。(デシリアライズしてくれる)
[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))] public class Profile { public string UserId { get; set; } public string DisplayName { get; set; } public string PictureUrl { get; set; } public string StatusMessage { get; set; } }
public async Task LoadProfileAsync() => Profile = await JSRuntime.InvokeAsync<Profile>("liff.getProfile").ConfigureAwait(false);
非同期関数の場合
戻り値にPromiseを返してくれるメソッドの場合、そのままInvokeAsyncで実行するだけで良いです。
- 実行結果(Promise.then() で受け取れるオブジェクト)を戻り値に返してくれる
- JS側でエラーとなった場合、C#では例外が投げられ、Exception.Messageプロパティでエラー内容( Promise.catch()で受け取れるオブジェクト)が確認できる
public async Task LoadProfileAsync() => Profile = await JSRuntime.InvokeAsync<Profile>("liff.getProfile").ConfigureAwait(false);
コールバック関数を受け取る関数の場合
liff.init()
関数が、非同期実行の結果を引数に渡したコールバック関数で受け取るようになっています。
当初は以下の様に、C#側に記述したコールバック関数をJS側で呼ぶようにしていました。
JavaScript側からC#で記述したコールバック処理を実行する(却下)
liff.init()
に渡したコールバック関数内でC#側で定義した関数を呼ぶJavaScriptの中継コードを用意
window.liffInterop = { init: function (dotNet) { liff.init( function (data) { dotNet.invokeMethod('OnInitSuccess', JSON.stringify(data)); }, function (error) { dotNet.invokeMethod('OnInitError', JSON.stringify({ code: error.code, message: error.message, stack: error.stack })); } ); } };
- C#側では、コールバックで実行したい処理をイベントに登録
- イベントを実行するメソッド
OnInitSuccess
とOnInitError
を[JSInvokable]
でマーク - JSInvokableなメソッドを持つオブジェクト(LiffClient)のインスタンスを
DotNetObjectRef
にラップしてJSRuntime.InvokeAsync
の引数に渡す
class LiffClient : ILiffClient { public event EventHandler<InitSuccessEventArgs> InitSuccess; public event EventHandler<LiffClientErrorEventArgs> InitError; public async Task InitializeAsync(IJSRuntime jSRuntime) { await JSRuntime.InvokeAsync<object>("liffInterop.init", DotNetObjectRef.Create(this)); } [JSInvokable] protected void OnInitSuccess(string data) { Data = JsonConvert.DeserializeObject<LiffData>(data); InitSuccess?.Invoke(this, new InitSuccessEventArgs(Data)); } [JSInvokable] protected void OnInitError(string error) { Error = error; InitError?.Invoke(this, new LiffClientErrorEventArgs(Error)); } }
これでも動くことは確認したのですが、大袈裟すぎてとても面倒です。そこで以下の様に対処することとしました。
コールバックを取るJavaScriptの関数をPromise に変換する
中間コードを以下の様に変更します。
window.liffInterop = { init: function () { return new Promise(function (resolve, reject) { liff.init( function (data) { resolve(JSON.stringify(data)); }, function (error) { reject(error); }); }); } };
C#側ではPromise化した関数を呼ぶだけでよくなります。かなりシンプルなコードになりました。
(戻り値 はLiffData
オブジェクトとしてそのまま受け取れるはずなのですが、 デシリアライズが失敗するようなので一旦文字列で受けて自前でデシリアライズしています。)
public async Task InitializeAsync(IJSRuntime jsRuntime) { var json = await jSRuntime.InvokeAsync<string>("liffInterop.init").ConfigureAwait(false); Data = JsonConvert.DeserializeObject<LiffData>(json); }
※ JS相互運用については以下のドキュメントをご確認ください docs.microsoft.com
Blazorで使えるLIFF(LINE Front-end Framework)のC#ライブラリを作りました
はじめに
「技術書典7」で頒布された LINE API HANDBOOK の第3章を「Blazor とAzure Functions で作る LIFFアプリケーション」というタイトルで書きました。
その際に、JavaScriptで書かれたLIFFのSDKをBlazor(client-side)用にC#でラップしたクラスライブラリ「liff-client-csharp」を作ったので紹介します。 github.com
- LIFFについて
LIFF はLINEアプリ上で動作するWebアプリケーションのフレームワークです。詳しくは以下を参照してください。
developers.line.biz
liff-client-csharp
「liff-client-csharp」では、LIFFのクライアントAPIのうち以下の機能をサポートしています。
また、ようやくpreviewが外れた.Net Core 3.0.100 に対応しています。
liff.init()
LIFFアプリを初期化します。このメソッドを実行すると、LIFF SDKの他のメソッドを実行できるようになります。liff.openWindow()
指定したURLをLINE内ブラウザまたは外部ブラウザで開きます。liff.getAccessToken()
現在のユーザーのアクセストークンを取得します。liff.getProfile()
現在のユーザーのプロフィールを取得します。liff.sendMessages()
ユーザーの代わりに、LIFFアプリが開かれているトーク画面にメッセージを送信します。liff.closeWindow()
LIFFアプリを閉じます。
(参考)LIFF APIリファレンス
※ LIFFのAPIには、LINE Things がらみのデバイス操作用のAPIも用意されているのですが、本ライブラリでは未対応となっています。
使用方法
1. NuGetでライブラリ LineDC.Liff を取得し、Blazor client-side(WebAssembly)のプロジェクトに追加
Install-Package LineDC.Liff -Version 0.6.0-preview
2. wwwroot/index.html のBody内にスクリプトの参照を追加
<body> ... <script src="https://d.line-scdn.net/liff/1.0/sdk.js"></script> <script src="_content/LineDC.Liff/liffInterop.js"></script> </body>
3. Startup.cs のConfigureServicesでILiffClientを登録
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddSingleton<ILiffClient, LiffClient>(); } }
4. 使用するページでILiffClientを使用する
各ページでは、@Injectディレクティブを用いることで ILiffClientの機能が利用可能となります。
@inject ILiffClient Liff
public interface ILiffClient { bool Initialized { get; } LiffData Data { get; } Profile Profile { get; } string AccessToken { get; } Task InitializeAsync(IJSRuntime jSRuntime); Task LoadProfileAsync(); Task<string> GetAccessTokenAsync(); Task SendMessagesAsync(object messages); Task CloseWindowAsync(); Task OpenWindowAsync(string url, bool external); void Reset(); }
以下のコードは、ページ初期化時のイベント(OnInitializedAsync)でLIFFの初期化と、ユーザープロフィールの取得を行い、取得した情報をページ内に表示する例です。
@page "/" @inject ILiffClient Liff @inject IJSRuntime JSRuntime <div class="card" style="width: 20rem;"> <img class="card-img" src="@Liff.Profile?.PictureUrl" alt="Loading image..." /> <div class="card-body"> <h5 class="card-title">@Liff.Profile?.DisplayName</h5> <p class="card-text">@Liff.Profile?.StatusMessage</p> </div> <ul class="list-group"> <li class="list-group-item">Language: @Liff.Data?.Language</li> <li class="list-group-item">Type: @Liff.Data?.Context.Type</li> <li class="list-group-item">ViewType: @Liff.Data?.Context.ViewType</li> <li class="list-group-item">UserId: @Liff.Data?.Context.UserId</li> @if (@Liff.Data?.Context.Type == ContextType.Utou) { <li class="list-group-item">UtouId: @Liff.Data?.Context.UtouId</li> } else if (@Liff.Data?.Context.Type == ContextType.Room) { <li class="list-group-item">RoomId: @Liff.Data?.Context.RoomId</li> } else if (@Liff.Data?.Context.Type == ContextType.Group) { <li class="list-group-item">GroupId: @Liff.Data?.Context.GroupId</li> } </ul> </div> @code{ protected override async Task OnInitializedAsync() { try { await Liff.InitializeAsync(JSRuntime); await Liff.LoadProfileAsync(); StateHasChanged(); } catch (Exception e) { await JSRuntime.InvokeAsync<object>("alert", e.ToString()); } } }
実装メモ
本ライブラリを実装した際のTipsをメモしておきます。
既存JavaScript ライブラリのBlazor用C#ラッパーを作る際の参考になれば幸いです。
C#のソースコードからPlantUMLのクラス図を作成するツールのバージョンアップとVS Codeの拡張を公開しました!
PlantUmlClassDiagramGenerator v1.1.0
以前に作成してGitHubに公開していた、C#のソースコードからPlantUMLのクラス図を作成するツール「PlantUmlClassDiagramGenerator」にプルリクエストが来ていたので、 久しぶりにバージョンアップしました!
以前の記事 pierre3.hatenablog.com
.Net Core global tools
「.Net Core 化したよ!」というプルリクエストをもらったのをきっかけに、.Net Core global tools として公開しています。
Windows以外のプラットフォームでも.Net Core SDKが入っていれば動きます。インストールも超簡単なので、ぜひお試しを!
アップデートの内容
オブジェクト間の関連を、プロパティ、フィールドの参照から作るようにしました。
組み込み型以外のフィールド、プロパティが以下の様に「関連」(A --> B)として作成されます。
また、フィールド、プロパティが初期化子で初期さされている場合は「集約」(A o-> B)として作成されます。
class ClassA{ public IList<string> Strings{get;} = new List<string>(); public Type1 Prop1{get;set;} public Type2 field1; } class Type1 { public int value1{get;set;} } class Type2{ public string string1{get;set;} public ExternalType Prop2 {get;set;} }
- PlantUML
@startuml class ClassA { } class Type1 { + value1 : int <<get>> <<set>> } class Type2 { + string1 : string <<get>> <<set>> } class "IList`1"<T> { } ClassA o-> "Strings<string>" "IList`1" ClassA --> "Prop1" Type1 ClassA --> "field1" Type2 Type2 --> "Prop2" ExternalType @enduml
この機能はコマンドライン引数に 「-createAssociation」スイッチを追加することで有効になります。表示するオブジェクト数が多い場合はごちゃごちゃしすぎるのでOFFにした方が良いかもしれません。
Visual Studio Code 拡張機能
ついでに、PlantUmlClassDiagramGeneratorを実行できるVisual Studio Codeの拡張機能を作りました! 単純にコマンドパレットから実行するだけなのですが、VS CodeにはPlantUMLをプレビュー表示できる拡張機能も公開されており、合わせて活用することでVS CodeによるC#の開発が捗ること間違いないしです!