65.9K
CodeProject 正在变化。 阅读更多。
Home

实现自定义WebHook(带持久存储)

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.90/5 (6投票s)

2015年11月22日

CPOL

3分钟阅读

viewsIcon

15723

本文主要解释了如何使用持久存储编写自定义 webhook,如何创建它们,以及自定义 webhook 上的示例源代码。 本文的目的只是给出编写自己的自定义 web hook 的一个想法。

引言

在深入研究自定义 WebHook 之前,让我简单描述一下 web hook,它背后的模式以及为什么要使用它们? WebHook 可以简单地解释为 HTTP 回调机制,它为连接可能位于不同位置的两个或多个服务提供了一个简单的发布者/订阅者模型。 当服务中发生事件时,会以 HTTP POST 请求的形式将通知发送到已注册的订阅者。 POST 请求包含有关事件的信息,这使得接收者可以采取相应的行动。

WebHook 使用发布-订阅消息模式,其中消息的发送者称为发布者,接收者称为订阅者。

webhook 模式的主要优点是您的应用程序不必定期调用 API。
相反,API 会在特定端点上调用您的应用程序,告知您发生了有趣的事情。
现在,我想您可能对 webhook 以及它们在幕后的工作方式有了一些了解。

实现自定义 WebHook

最近,我们有机会在我们的一个项目中实现 webhook。 项目中的情况要求我们在当前的 ASP.NET MVC 5.0 代码库中实现自定义 webhook。 感谢 Microsoft.AspNet.WebHooks.Custom.dll 使我的工作更容易。 Microsoft.AspNet.WebHooks.Custom.dll 使用类 MemoryWebHookStore,它将 webhook 信息存储在内存中。 类 MemoryWebHookStore 使用线程安全集合 *ConcurrentDictionary* 来存储 webhook 详细信息。 只要应用程序位于演示服务器中,将 webhook 详细信息存储在内存中就非常好。 但是,在真正的生产环境中,我们需要将 webhook 详细信息存储在持久存储中,并且我们没有选择使用 Azure 表,因为该应用程序将部署在不同的服务器上。 所以我们必须以某种方式完成这项任务。 现在,在撰写本文时,我们有一个关于在 SQL Server 中存储数据的新 web hook 更新,Microsoft.AspNet.WebHooks.Custom.SqlStorage dll 现在可以下载,它将 WebHook 详细信息存储在 SQL Server 中。 但在我们的实现时,Microsoft.AspNet.WebHooks.Custom.SqlStorage.dll 尚未发布,我们必须编写自己的机制来将 WebHook 存储在持久存储中。

让我解释一下我们是如何实现这一目标的。 基本上,WebHook 订阅是通过一个名为 IWebHookStore 的接口来管理的,该接口提供了一个用于查询、插入、更新和删除订阅的抽象。
默认的 IWebHookStore 实现仅在内存中。 这里的想法是编写一个实现 IWebHookStore 接口的类,并将依赖项传递给 WebHookManager

示例代码实现

我们创建了一个如下所示的持久存储类,并将其实例传递给 WebHookManager。

IWebHookStore _whStore = new PersistentWebHookStore();
IWebHookManager _whManager = new WebHookManager(_whStore, new TraceLogger());

让我们编写一个 PersistentWebHookStore 类并实现 Microsoft.AspNet.WebHooks 中提供的 IWebHookStore 接口

    namespace Microsoft.AspNet.WebHooks
    {
        public interface IWebHookStore
        {
            Task DeleteAllWebHooksAsync(string user);
            Task DeleteWebHookAsync(string user, string id);
            Task> GetAllWebHooksAsync(string user);
            Task InsertWebHookAsync(string user, WebHook webHook);
            Task LookupWebHookAsync(string user, string id);
            Task> QueryWebHooksAsync(string user, IEnumerable actions);
            Task UpdateWebHookAsync(string user, WebHook webHook);
        }
    }
    public class PersistentWebHookStore : IWebHookStore
    {
        #region Member Variables

        private readonly IWebHookRepository _webHookRepository = null;

        #endregion

        #region Constructor

        public PersistentWebHookStore()
        {
            _webHookRepository = new WebHookRepository();
        }

        #endregion

        #region IWebHookStore Methods
        
        //Register or in other words inserts a new web hook for a user.
        public Task<StoreResult> InsertWebHookAsync(string user, WebHook webHook)
        {
            if (!string.IsNullOrWhiteSpace(user) && webHook != null)
            {
                // Do the insert logic as you wish, here i am using a WebHook Repository 
                // to insert the details to SQL Server.The web hook repository uses  
                // EntityFrameWork to insert the web hook details to DB.
                user = Normalize(user);                
                bool isInserted = _webHookRepository.Insert(user, webHook);
                StoreResult result = isInserted ? StoreResult.Success : StoreResult.Conflict;
                return Task.FromResult(result);
            }
            else
            {
                throw new Exception("Values expected for either user or webHook");
            }
        }

        public Task<StoreResult> UpdateWebHookAsync(string user, WebHook webHook)
        {
            bool isUpdated = false;

            // Do the web hook update logic here.

            StoreResult result = isUpdated ? StoreResult.Success : StoreResult.Conflict;
            return Task.FromResult(result);
        }

        public Task<StoreResult> DeleteWebHookAsync(string user, string id)
        {
            bool isDeleted = false;

            // Do the web hook delete logic here.

            StoreResult result = isDeleted ? StoreResult.Success : StoreResult.Conflict;
            return Task.FromResult(result);
        }

        public Task<ICollection<WebHook>> GetAllWebHooksAsync(string user)
        {
            ICollection result = null;

            // Do the logic to get all web hooks against a user.

            return Task.FromResult(result);
        }
        
        ...
        ...

        #endregion
    }

就这样!。 从这篇文章中,我只想解释一下在 Microsoft.AspNet.WebHooks.Custom.SqlStorage 类发布前几个月,我是如何使用持久存储实现自定义 WebHook 的,该类完全做了同样的事情。

参考

http://blogs.msdn.com/b/webdev/archive/2015/09/04/introducing-microsoft-asp-net-webhooks-preview.aspx

http://blogs.msdn.com/b/webdev/archive/2015/09/15/sending-webhooks-with-asp-net-webhooks-preview.aspx

http://blogs.msdn.com/b/webdev/archive/2015/11/07/updates-to-microsoft-asp-net-webhooks-preview.aspx

https://nuget.net.cn/packages/Microsoft.AspNet.WebHooks.Custom.SqlStorage

https://en.wikipedia.org/wiki/Webhook

© . All rights reserved.