Introduction
Before going into custom WebHook let me give you a small description on web hook, the pattern behind it and why are they used for? A WebHook can be simply explained as an HTTP callback mechanism which provides a simple publisher / subscriber model for wiring up two or more services which may live on different location.When an event happens in a service, a notification is sent in the form of an HTTP POST request to the registered subscribers. The POST request contains information about the event which makes it possible for the receiver to act accordingly.
WebHook uses a publish–subscribe messaging pattern where the senders of messages are called publishers and the receivers are called subscribers.
The main advantage of the webhooks pattern is that your application doesn’t have to make periodic calls to APIs.
Instead, APIs will call your application on a specific endpoint informing that something interesting has happened.
Now, i guess you may got some idea on webhooks and how they are working behind the scene.
Implementing Custom WebHook
Recently we got a chance to implement webhook in one of our project. The situation in the project demands us to implement custom webhook in our current code base which is in ASP.NET MVC 5.0.Thanks to Microsoft.AspNet.WebHooks.Custom.dll which makes my work very easier. Microsoft.AspNet.WebHooks.Custom.dll uses the class MemoryWebHookStore which stores the webhook information in-memory. The class MemoryWebHookStore make use of a thread safe collection ConcurrentDictionary to store the webhook details. Storing the webhook details in-memory was pretty fine as long as the application was in a demo server. However in the real production environment we need to store webhook details in a persistent storage and we dont have a choice to use Azure table since the application is going to be deployed on a different server. So we have to achieve this task some how. Now at the time of writing this article, we have a new web hook update on storing data in a SQL server, Microsoft.AspNet.WebHooks.Custom.SqlStorage dll is now avaialable for download which stores the WebHook details in a SQL server. But at the time of our implementation, Microsoft.AspNet.WebHooks.Custom.SqlStorage.dll was not yet released and we have write our own mechanism to store the WebHook in a persistent storage.
Let me explain how we have achieved this. Basically WebHook subscriptions are managed through an interface called IWebHookStore which provide an abstraction for querying, inserting, updating, and deleting subscriptions.
The default IWebHookStore implementation is in-memory-only. The idea here is to write a class which implements the IWebHookStore interface and pass the dependency to WebHookManager.
Sample code implementation
We created a Persistent storage class like below and passed its instane to WebHookManager.
IWebHookStore _whStore = new PersistentWebHookStore();
IWebHookManager _whManager = new WebHookManager(_whStore, new TraceLogger());
Lets write a PersistentWebHookStore class and implement the IWebHookStore interface available in Microsoft.AspNet.WebHooks
namespace Microsoft.AspNet.WebHooks
{
public interface IWebHookStore
{
Task DeleteAllWebHooksAsync(string user);
Task<storeresult> DeleteWebHookAsync(string user, string id);
Task<icollection<webhook>> GetAllWebHooksAsync(string user);
Task<storeresult> InsertWebHookAsync(string user, WebHook webHook);
Task<webhook> LookupWebHookAsync(string user, string id);
Task<icollection<webhook>> QueryWebHooksAsync(string user, IEnumerable<string> actions);
Task<storeresult> UpdateWebHookAsync(string user, WebHook webHook);
}
}
</storeresult>
public class PersistentWebHookStore : IWebHookStore
{
#region Member Variables
private readonly IWebHookRepository _webHookRepository = null;
#endregion
#region Constructor
public PersistentWebHookStore()
{
_webHookRepository = new WebHookRepository();
}
#endregion
#region IWebHookStore Methods
public Task<StoreResult> InsertWebHookAsync(string user, WebHook webHook)
{
if (!string.IsNullOrWhiteSpace(user) && webHook != null)
{
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;
StoreResult result = isUpdated ? StoreResult.Success : StoreResult.Conflict;
return Task.FromResult(result);
}
public Task<StoreResult> DeleteWebHookAsync(string user, string id)
{
bool isDeleted = false;
StoreResult result = isDeleted ? StoreResult.Success : StoreResult.Conflict;
return Task.FromResult(result);
}
public Task<ICollection<WebHook>> GetAllWebHooksAsync(string user)
{
ICollection<webhook> result = null;
return Task.FromResult(result);
}
...
...
#endregion
}
</webhook>
that's all!. From this ariticle i just want to explain how i have implemented custom WebHook using persistent storage, few months before the release of Microsoft.AspNet.WebHooks.Custom.SqlStorage
class which excatly does the same thing.
Reference
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://www.nuget.org/packages/Microsoft.AspNet.WebHooks.Custom.SqlStorage
https://en.wikipedia.org/wiki/Webhook