Avanade Beef で変更通知を Azure Service Bus に送信する
はじめに
Avanade Beef (以下、Beef) は ASP.NET Core をベースとする Web API の自動生成ツールです。
概要については以下のスライドもご覧ください。
Beef ではイベント駆動型のアーキテクチャを採用しています。これにより外部のシステムとの連携や非同期でのジョブの実行を実現することができます。ただ例によってあまり情報がないため、順を追って実装方法を説明していきたいと思います。
サンプル コード
実行手順
プロジェクトの作成
v5 からデータ ソースの指定の方法が変わりました。Entity Framework を使用する場合は SqlServer
です。
dotnet new beef --company Karamem0 --appname SampleApplication --datasource SqlServer
Business
プロジェクトに CoreEx.Azure を追加します。
dotnet add package CoreEx.Azure
エラーが出る場合はそのほかの CoreEx のライブラリとバージョン (>=2.7.0) を合わせてください。
テーブル定義
Product
テーブルを作成します。
CREATE TABLE [SampleApplication].[Product] (
[ProductId] UNIQUEIDENTIFIER NOT NULL DEFAULT (NEWSEQUENTIALID()) PRIMARY KEY,
[ProductName] NVARCHAR (255) NOT NULL,
[Price] DECIMAL (15, 0) NOT NULL,
[CreatedBy] NVARCHAR(250) NULL,
[CreatedDate] DATETIME2 NULL,
[UpdatedBy] NVARCHAR(250) NULL,
[UpdatedDate] DATETIME2 NULL
);
コードの修正
Database/database.beef-5.yaml
Entity Framework のモデルを定義します。
schema: SampleApplication
tables:
- name: Product
efModel: true
コードを自動生成します。
dotnet run all
CodeGen/entity.beef-5.yaml
エンティティを定義します。
eventSubjectRoot: Karamem0
eventActionFormat: PastTense
eventSourceRoot: Karamem0/SampleApplication
eventSourceKind: Relative
eventPublish: DataSvc
webApiAutoLocation: true
refDataText: true
entities:
- name: Product
text: Product
collection: true
collectionResult: true
get: true
getAll: true
create: true
update: true
delete: true
validator: ProductValidator
webApiRoutePrefix: products
autoImplement: EntityFramework
entityFrameworkModel: EfModel.Product
properties:
- name: ProductId
type: Guid
primaryKey: true
- name: ProductName
type: string
- name: Price
type: decimal
- name: ChangeLog
type: ChangeLog
コードを自動生成します。
dotnet run all
Business/DataSvc/Generated/ProductDataSvc.cs
自動生成されたコードは以下のようになっています。
/// <summary>
/// Creates a new <see cref="Product"/>.
/// </summary>
/// <param name="value">The <see cref="Product"/>.</param>
/// <returns>The created <see cref="Product"/>.</returns>
public Task<Product> CreateAsync(Product value) => DataSvcInvoker.Current.InvokeAsync(this, async _ =>
{
var __result = await _data.CreateAsync(value ?? throw new ArgumentNullException(nameof(value))).ConfigureAwait(false);
_events.PublishValueEvent(__result, new Uri($"karamem0/sampleapplication/product/{__result.ProductId}", UriKind.Relative), $"Karamem0.SampleApplication.Product", "Created");
return _cache.SetValue(__result);
}, new InvokerArgs { EventPublisher = _events });
この PublishValueEvent
メソッドが Azure Service Bus へのイベントを発火するところになります。
Api/Startup.cs
Azure Service Bus の Client および Sender を追加します。
// Add the event publishing; this will need to be updated from the logger publisher to the actual as appropriate.
services.AddEventDataFormatter()
- .AddLoggerEventPublisher();
+ .AddEventDataSerializer()
+ .AddEventPublisher()
+ .AddAzureServiceBusSender()
+ .AddAzureServiceBusClient();
Api/appsettings.json
Azure Service Bus への接続文字列とキュー/トピック名を指定します。
{
...
"ConnectionStrings": {
"Database": "Data Source=.;Initial Catalog=Karamem0.SampleApplication;Integrated Security=True;TrustServerCertificate=true"
},
+ "ServiceBusConnection": "Endpoint=sb://{{service-name}}.servicebus.windows.net/;SharedAccessKeyName={{access-key-name}};SharedAccessKey={{access-key}}",
+ "ServiceBusSender": {
+ "QueueOrTopicName": "SampleApplication"
+ },
...
}
実行結果
実際にデバッグして Swagger から POST すると Azure Service Bus にキューが入るのがわかります。本文には追加したアイテムの情報が入っています。
カスタム プロパティも設定されています。
おわりに
今回のようなシンプルな変更通知の他に、分散システムで使用できる Transactional Outbox パターンも利用できます。詳しくは以下のドキュメントをご確認いただければと思います。
Discussion