[ASP.NET]Microsoft ASP.NET WebHook - 2

在前篇「Microsoft ASP.NET WebHook Preview」中說明透過2個 WebAPI 專案來演示,
Sender 專案需要登入系統後才能將 WebHook 的 URL 註冊到資料庫之中,
但是在實際的應用之中,或許需要的是透過一個簡單的 UI 來管理這些 WebHook 資訊。
本文就介紹如何透過 Windows Forms 程式來新增 WebHook 到 SQL Server 之中,並且發送訊息到 Receiver 專案。

其實 WebHook 就是簡單的 Event Subscriptions 的關係,如下圖,

如上圖所示,我們要新增一個 Windows Forms App 來新增 WebHook Subscriptions 及發送通知。

首先新增  Windows Forms App 專案,然後加入 Microsoft.AspNet.WebHooks.Custom.SqlStorage 套件,

在 app.config 中的 connectionStrings 請加入 MS_SqlStoreConnectionString 的設定,如下,

<connectionStrings>
	<add name="MS_SqlStoreConnectionString" 
	  connectionString="Data Source={你的DBServer};Initial Catalog={DB Name};user id={userid};password={password};"
	  providerName="System.Data.SqlClient" />
</connectionStrings>

在 DB 中,請新增 [WebHooks].[WebHooks] 這個 Table,如下,

CREATE TABLE [WebHooks].[WebHooks](
	[User] [nvarchar](256) NOT NULL,
	[Id] [nvarchar](64) NOT NULL,
	[ProtectedData] [nvarchar](max) NOT NULL,
	[RowVer] [timestamp] NOT NULL,
 CONSTRAINT [PK_WebHooks.WebHooks] PRIMARY KEY CLUSTERED 
(
	[User] ASC,
	[Id] ASC
)ON [PRIMARY]
) 

因為筆者的 Logger 是使用 TraceLogger,所以在 app.config 中也要設定如下,

<system.diagnostics>
	<trace autoflush="true" indentsize="4">
	  <listeners>
		<add name="myListener" type="System.Diagnostics.TextWriterTraceListener" 
			 initializeData="TextWriterOutput.log" />
		<remove name="Default" />
	  </listeners>
	</trace>
</system.diagnostics>

再來就是拉 UI,如下,

程式中,設定全域變數,如下,

public IWebHookManager Manager { get; set; }
public IWebHookStore Store { get; set; }
public ILogger Logger { get; set; }

Load Method 要初始設定 Logger, Store 及 Manager , 如下,

private void Form1_Load(object sender, EventArgs e)
{
	//設定 Logger
	Logger = new TraceLogger();
	//設定 SQL 來存 WebHook 的資料
	Store = SqlWebHookStore.CreateStore(Logger);
	//Sender 使用 DataflowWebHookSender 
	var webhookSender = new DataflowWebHookSender(Logger);

	Manager = new WebHookManager(Store, webhookSender, Logger);
}

在「Register WebHook」 Button ,按下後,要新增一個 WebHook 然後呼叫  Store 的 InsertWebHookAsync Method,
將資料存到 SQL Server 之中,如下,

private async void btnRegisterHook_Click(object sender, EventArgs e)
{
	var webhook = new WebHook
	{
		Secret=txtSecret.Text,
		WebHookUri=new Uri(txtWebHookUrl.Text),
		
	};
	// 這個值在 Send 通知時,會用 ActionId 去 Filter, 
	// * 或是 ActionId == txtActionFilter.Text
	webhook.Filters.Add(txtActionFilter.Text);

	var result = await Store.InsertWebHookAsync(txtUserId.Text, webhook);
	MessageBox.Show(result.ToString());
}

而在「發送通知」 Button ,按下後,會從 Store 中取出可通知的 WebHook 訂閱資訊,
然後將內容發送給這些 WebHook 訂閱者,如下,

private async void btnSendNotifyAll_Click(object sender, EventArgs e)
{
	var notifyBody = JObject.Parse(txtNotifyBody.Text);
	//透過 WebHookManager 來傳送通知
	var result = await Manager.NotifyAllAsync(txtActionId.Text, notifyBody);
}


測試時,相關的資訊會寫到 bin 目錄中的 TextWriterOutput.log 檔案中,
可以透過 Log 來看傳送是否OK,如下,

筆者在測試過程中,一開始通知並沒有成功,後來看 WebHook Source 才知道 webhook 的 Filters 要給值。
如果您想要知道 NotifyAllAsync 是如何取出要通知的 WebHook 訂閱資料,
可以從 github 「WebHookSaveSendFromWinForms」 下載筆者的測試專案來測試看看。

var notifications = new NotificationDictionary[] { new NotificationDictionary(txtActionId.Text, notifyBody) };
string[] actions = notifications.Select(n => n.Action).ToArray();
Func<WebHook, string, bool> predicate = null;
var webHooks = await Store.QueryWebHooksAcrossAllUsersAsync(actions, predicate);
var wkItems = GetWorkItems(webHooks, notifications);
var webhookSender = new DataflowWebHookSender(Logger);
//webhookSender.SendWebHookWorkItemsAsync 就相當於 foreach ... LaunchWebHook
foreach (var item in wkItems)
{
    await LaunchWebHook(item);
}

測試時,請開啟2個VS.NET專案,分別 debug 哦!

 

註:筆者目前的 Receiver 是使用 MS BOT 的 WebAPI 專案,這樣就可以透過 BOT 通知到使用者。

參考資料

Microsoft ASP.NET WebHook Preview

WebHookSaveSendFromWinForms

aspnet/WebHooks (github)

Hi, 

亂馬客Blog已移到了 「亂馬客​ : Re:從零開始的軟體開發生活

請大家繼續支持 ^_^