November 7th, 2015

Updates to Microsoft ASP.NET WebHooks Preview

We just released Beta4 of ASP.NET WebHooks Preview with a nice set of new features based on feedback and help from the community! Always let us know what you think – either by raising a issue on GitHub or pinging me on twitter. You can get the update from nuget.org by looking for the packages under Microsoft.AspNet.WebHooks.*. If you haven’t heard about ASP.NET WebHooks then you may want to look at Introducing Microsoft ASP.NET WebHooks Preview.

Here’s what’s new:

Storing WebHook Registrations in SQL

This feature is from a pull request from Ryan Posener — thanks! It enables storing Custom WebHook Registrations in a SQL server. Before this we could store them in Azure Table Storage, but with support for SQL, developers have much more flexibility in where to store them. Now, when setting up custom WebHooks, you can include the Microsoft.AspNet.WebHooks.Custom.SqlStorage package and wire it up in the WebApiConfig.cs file:

public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

// Load basic support for sending WebHooks
config.InitializeCustomWebHooks();

// Use SQL for persisting subscriptions
config.InitializeCustomWebHooksSqlStorage();

// Load Web API controllers for managing subscriptions
config.InitializeCustomWebHooksApis();
}
}

Set the connection string in the Web.config file of your Web Application project, something like this:

<configuration>
...
<connectionStrings>
...
<add name="MS_SqlStoreConnectionString"
connectionString="Data Source=(LocalDb)MSSQLLocalDB;
Initial Catalog=WebHooks-20151029053732;Integrated Security=True"

providerName="System.Data.SqlClient" />
</connectionStrings>
...
</configuration>

Finally, you need to initialize Entity Framework Code First Migrations to create and initialize the DB. In Visual Studio, open Package Manager Console from the ToolsNuget Package Manager menu and make sure your Web Application project is the Default Project:

 
NugetConsole

From the Package Manager Console run the following three commands, one after another, for initializing migrations and to initiate the DB:

Enable-Migrations -ContextAssemblyName Microsoft.AspNet.WebHooks.Custom.SqlStorage
Add-Migration WebHookStoreInitialDB
Update-Database

That’s it – you are now ready to store WebHook registrations in your SQL server of choice! For a full example of how to use this, please see our new Custom WebHooks sample projects below.

Custom WebHooks Sample Projects

We added two Custom WebHook sample projects following the path for setting up Custom WebHooks described in the blog Sending WebHooks with ASP.NET WebHooks Preview. The CustomSender project covers the sending part of Custom WebHooks and the CustomReceiver project covers the receiving part. These sample projects (along with the other sample projects) hopefully make it simpler to try things out.

Slack Slash Commands

Slash Commands enable Slack users to interact with external services directly from Slack. Slash commands start with a slash ‘/’ and can be wired up much like Outgoing WebHooks. That is, you can define a Slash Command to trigger an HTTP request with additional data to do something, for example:

/henrik do something!

To set up a Slash Command you just follow the instructions for a Slash Command like this:

SlashCommand

On the ASP.NET WebHooks side, the setup works exactly as for Slack Outbound WebHooks described in the blog Integrating with Slack Using ASP.NET WebHooks Preview. In addition, there now is a Slack sample which you can also use.

Instagram Receiver Improvements

We added some more types making it simpler to use Instagram WebHooks and also added a sample illustrating the new model. Here’s a sample handler looking for both image and videos (if present):

public override async Task ExecuteAsync(string generator, WebHookHandlerContext context)
{
// Get the WebHook client
InstagramWebHookClient client = Dependencies.Client;

// Convert the incoming data to a collection of InstagramNotifications
var notifications = context.GetDataOrDefault<InstagramNotificationCollection>();
foreach (var notification in notifications)
{
// Use WebHook client to get detailed information about the posted media
JArray entries = await client.GetRecentGeoMedia(context.Id, notification.ObjectId);
foreach (JToken entry in entries)
{
InstagramPost post = entry.ToObject<InstagramPost>();

// Image information
if (post.Images != null)
{
InstagramMedia thumbnail = post.Images.Thumbnail;
InstagramMedia lowRes = post.Images.LowResolution;
InstagramMedia stdRes = post.Images.StandardResolution;
}

// Video information
if (post.Videos != null)
{
InstagramMedia lowBandwidth = post.Videos.LowBandwidth;
InstagramMedia lowRes = post.Videos.LowResolution;
InstagramMedia stdRes = post.Videos.StandardResolution;
}

// Get direct links and sizes of media
Uri link = post.Link;
}
}
}

Receivers Behind Firewalls

In certain cases, a WebHook receiver may sit behind a firewall or gateway that forwards requests as non-HTTPS requests, i.e. just as plain-text HTTP. In this case, the default WebHook receiver check that requires use of HTTPS will fail preventing the WebHook from being processed. This check can now be suppressed by setting the ‘MS_WebHookDisableHttpsCheck’ Application Setting to ‘true’. That is, if ‘true’ this will cause regular HTTP requests to go through. Obviously this setting should be used with caution!

WebHookManager Updates

We added a constructor for WebHookManager which enables wiring up the default IWebHookManager implementation with a custom retry policy and the level of concurrency used when sending out event notifications in the form of WebHook requests. Here is an example of initializing Custom WebHooks using Autofac Dependency Injection engine registering WebHookManager with a custom policy:

public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

// Load basic support for sending WebHooks
config.InitializeCustomWebHooks();

// Load Azure Storage or SQL for persisting subscriptions
config.InitializeCustomWebHooksAzureStorage();

// Load Web API controllers for managing subscriptions
config.InitializeCustomWebHooksApis();

// Create custom WebHookManager with custom retry policy
ILogger logger = config.DependencyResolver.GetLogger();
IWebHookStore store = config.DependencyResolver.GetStore();
IWebHookManager manager = new WebHookManager(store, logger, new TimeSpan[] { }, null);


// Register WebHookManager with Autofac
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterInstance(manager).As<IWebHookManager>().SingleInstance();

// Register MVC and Web API controllers with Autofac
Assembly currentAssembly = Assembly.GetExecutingAssembly();
builder.RegisterApiControllers(currentAssembly);
builder.RegisterControllers(currentAssembly);

// Build the Autofac container and set it as the dependency resolver for both MVC and Web API
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}

We also added a new generic JSON WebHook receiver, but we will demonstrate that in a separate blog so stay tuned 🙂

Have fun and keep the feedback coming!

Henrik