{"id":6031,"date":"2015-11-07T08:56:48","date_gmt":"2015-11-07T08:56:48","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/webdev\/2015\/11\/07\/updates-to-microsoft-asp-net-webhooks-preview\/"},"modified":"2023-09-19T11:37:29","modified_gmt":"2023-09-19T18:37:29","slug":"updates-to-microsoft-asp-net-webhooks-preview","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/updates-to-microsoft-asp-net-webhooks-preview\/","title":{"rendered":"Updates to Microsoft ASP.NET WebHooks Preview"},"content":{"rendered":"<p>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 \u2013 either by <a href=\"https:\/\/github.com\/aspnet\/webhooks\/issues\">raising a issue on GitHub<\/a> or <a href=\"https:\/\/twitter.com\/frystyk\">pinging me on twitter<\/a>. You can get the update from <a href=\"http:\/\/nuget.org\">nuget.org<\/a> by looking for the packages under <a href=\"https:\/\/www.nuget.org\/packages?q=Microsoft.AspNet.WebHooks\">Microsoft.AspNet.WebHooks.*<\/a>. If you haven\u2019t heard about ASP.NET WebHooks then you may want to look at <a href=\"http:\/\/blogs.msdn.com\/b\/webdev\/archive\/2015\/09\/04\/introducing-microsoft-asp-net-webhooks-preview.aspx\">Introducing Microsoft ASP.NET WebHooks Preview<\/a>.<\/p>\n<p>Here\u2019s what\u2019s new:<\/p>\n<h3>Storing WebHook Registrations in SQL<\/h3>\n<p>This feature is from a <a href=\"https:\/\/github.com\/aspnet\/WebHooks\/pull\/19\">pull request from Ryan Posener<\/a> &#8212; thanks! It enables storing <a href=\"http:\/\/blogs.msdn.com\/b\/webdev\/archive\/2015\/09\/15\/sending-webhooks-with-asp-net-webhooks-preview.aspx\">Custom WebHook Registrations<\/a> 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 <a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.AspNet.WebHooks.Custom.SqlStorage\">Microsoft.AspNet.WebHooks.Custom.SqlStorage<\/a> package and wire it up in the <strong>WebApiConfig.cs<\/strong> file:<\/p>\n<div id=\"codeSnippetWrapper\">\n<pre id=\"codeSnippet\"><span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">static<\/span> <span style=\"color: #0000ff\">class<\/span> WebApiConfig<br \/>{<br \/>    <span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">static<\/span> <span style=\"color: #0000ff\">void<\/span> Register(HttpConfiguration config)<br \/>    {<br \/>        <span style=\"color: #008000\">\/\/ Web API routes<\/span><br \/>        config.MapHttpAttributeRoutes();<br \/>        config.Routes.MapHttpRoute(<br \/>            name: <span style=\"color: #006080\">&quot;DefaultApi&quot;<\/span>,<br \/>            routeTemplate: <span style=\"color: #006080\">&quot;api\/{controller}\/{id}&quot;<\/span>,<br \/>            defaults: <span style=\"color: #0000ff\">new<\/span> { id = RouteParameter.Optional }<br \/>        );<br \/> <br \/>        <span style=\"color: #008000\">\/\/ Load basic support for sending WebHooks<\/span><br \/>        config.InitializeCustomWebHooks();<br \/> <br \/>        <span style=\"color: #008000\">\/\/ Use SQL for persisting subscriptions<\/span><br \/>        <font style=\"background-color: #ffff00\">config.InitializeCustomWebHooksSqlStorage();<\/font><br \/> <br \/>        <span style=\"color: #008000\">\/\/ Load Web API controllers for managing subscriptions<\/span><br \/>        config.InitializeCustomWebHooksApis();<br \/>    }<br \/>}<\/pre>\n<p><\/div>\n<p>Set the connection string in the <strong>Web.config<\/strong> file of your Web Application project, something like this:<\/p>\n<div id=\"codeSnippetWrapper\">\n<pre id=\"codeSnippet\"><span style=\"color: #0000ff\">&lt;<\/span><span style=\"color: #800000\">configuration<\/span><span style=\"color: #0000ff\">&gt;<\/span><br \/>  ...<br \/>  <span style=\"color: #0000ff\">&lt;<\/span><span style=\"color: #800000\">connectionStrings<\/span><span style=\"color: #0000ff\">&gt;<\/span><br \/>    ...<br \/>    <span style=\"color: #0000ff\">&lt;<\/span><span style=\"color: #800000\">add<\/span> <span style=\"color: #ff0000\">name<\/span><span style=\"color: #0000ff\">=&quot;<font style=\"background-color: #ffff00\">MS_SqlStoreConnectionString<\/font>&quot;<\/span><br \/>      <span style=\"color: #ff0000\">connectionString<\/span><span style=\"color: #0000ff\">=&quot;Data Source=(LocalDb)MSSQLLocalDB;<br \/>                        Initial Catalog=WebHooks-20151029053732;Integrated Security=True&quot;<\/span><br \/>      <span style=\"color: #ff0000\">providerName<\/span><span style=\"color: #0000ff\">=&quot;System.Data.SqlClient&quot;<\/span> <span style=\"color: #0000ff\">\/&gt;<\/span><br \/>  <span style=\"color: #0000ff\">&lt;\/<\/span><span style=\"color: #800000\">connectionStrings<\/span><span style=\"color: #0000ff\">&gt;<\/span><br \/>  ...<br \/><span style=\"color: #0000ff\">&lt;\/<\/span><span style=\"color: #800000\">configuration<\/span><span style=\"color: #0000ff\">&gt;<\/span><\/pre>\n<p>Finally, you need to initialize <a href=\"https:\/\/msdn.microsoft.com\/en-us\/data\/jj591621.aspx\">Entity Framework Code First Migrations<\/a> to create and initialize the DB. In Visual Studio, open <strong>Package Manager Console<\/strong> from the <strong>ToolsNuget Package Manager<\/strong> menu and make sure your Web Application project is the Default Project:<\/div>\n<div>&#160;<\/div>\n<div><a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2015\/11\/4744.NugetConsole_thumb_0EC527D9.png\"><img decoding=\"async\" title=\"NugetConsole\" style=\"border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;border-top-width: 0px;margin-right: auto\" border=\"0\" alt=\"NugetConsole\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2015\/11\/4744.NugetConsole_thumb_0EC527D9.png\" width=\"600\" height=\"148\" \/><\/a><\/div>\n<p>From the Package Manager Console run the following three commands, one after another, for initializing migrations and to initiate the DB:<\/p>\n<div id=\"codeSnippetWrapper\">\n<pre id=\"codeSnippet\">Enable-Migrations -ContextAssemblyName Microsoft.AspNet.WebHooks.Custom.SqlStorage<br \/>Add-Migration WebHookStoreInitialDB<br \/>Update-Database<\/pre>\n<p><\/div>\n<p>That\u2019s it \u2013 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.<\/p>\n<h3>Custom WebHooks Sample Projects<\/h3>\n<p>We added two Custom WebHook sample projects following the path for setting up Custom WebHooks described in the blog <a href=\"http:\/\/blogs.msdn.com\/b\/webdev\/archive\/2015\/09\/15\/sending-webhooks-with-asp-net-webhooks-preview.aspx\">Sending WebHooks with ASP.NET WebHooks Preview<\/a>. The <a href=\"https:\/\/github.com\/aspnet\/WebHooks\/tree\/dev\/samples\/CustomSender\">CustomSender project<\/a> covers the sending part of Custom WebHooks and the <a href=\"https:\/\/github.com\/aspnet\/WebHooks\/tree\/dev\/samples\/CustomReceiver\">CustomReceiver project<\/a> covers the receiving part. These sample projects (along with the other sample projects) hopefully make it simpler to try things out. <\/p>\n<h3>Slack Slash Commands<\/h3>\n<p><a href=\"https:\/\/api.slack.com\/slash-commands\">Slash Commands<\/a> enable Slack users to interact with external services directly from Slack. Slash commands start with a slash \u2018\/\u2019 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:<\/p>\n<div id=\"codeSnippetWrapper\">\n<pre id=\"codeSnippet\">\/henrik do something!<\/pre>\n<p><\/div>\n<p>To set up a Slash Command you just follow the instructions for a Slash Command like this:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2015\/11\/0451.SlashCommand_thumb_7805E04F.png\"><img decoding=\"async\" title=\"SlashCommand\" style=\"border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;border-top-width: 0px;margin-right: auto\" border=\"0\" alt=\"SlashCommand\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2015\/11\/0451.SlashCommand_thumb_7805E04F.png\" width=\"600\" height=\"418\" \/><\/a><\/p>\n<p>On the ASP.NET WebHooks side, the setup works exactly as for Slack Outbound WebHooks described in the blog <a href=\"http:\/\/blogs.msdn.com\/b\/webdev\/archive\/2015\/09\/06\/receiving-slack-webhooks-with-asp-net-webhooks.aspx\">Integrating with Slack Using ASP.NET WebHooks Preview<\/a>. In addition, there now is a <a href=\"https:\/\/github.com\/aspnet\/WebHooks\/tree\/master\/samples\/\">Slack sample<\/a> which you can also use.<\/p>\n<h3>Instagram Receiver Improvements<\/h3>\n<p>We added some more types making it simpler to use Instagram WebHooks and also added a <a href=\"https:\/\/github.com\/aspnet\/\">sample<\/a> illustrating the new model. Here\u2019s a sample handler looking for both image and videos (if present):<\/p>\n<div id=\"codeSnippetWrapper\">\n<pre id=\"codeSnippet\"><span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">override<\/span> async Task ExecuteAsync(<span style=\"color: #0000ff\">string<\/span> generator, WebHookHandlerContext context)<br \/>{<br \/>    <span style=\"color: #008000\">\/\/ Get the WebHook client<\/span><br \/>    InstagramWebHookClient client = Dependencies.Client;<br \/> <br \/>    <span style=\"color: #008000\">\/\/ Convert the incoming data to a collection of InstagramNotifications<\/span><br \/>    var notifications = context.GetDataOrDefault&lt;InstagramNotificationCollection&gt;();<br \/>    <span style=\"color: #0000ff\">foreach<\/span> (var notification <span style=\"color: #0000ff\">in<\/span> notifications)<br \/>    {<br \/>        <span style=\"color: #008000\">\/\/ Use WebHook client to get detailed information about the posted media<\/span><br \/>        JArray entries = await client.GetRecentGeoMedia(context.Id, notification.ObjectId);<br \/>        <span style=\"color: #0000ff\">foreach<\/span> (JToken entry <span style=\"color: #0000ff\">in<\/span> entries)<br \/>        {<br \/>            InstagramPost post = entry.ToObject&lt;InstagramPost&gt;();<br \/> <br \/>            <span style=\"color: #008000\">\/\/ Image information<\/span><br \/>            <span style=\"color: #0000ff\">if<\/span> (post.Images != <span style=\"color: #0000ff\">null<\/span>)<br \/>            {<br \/>                InstagramMedia thumbnail = post.Images.Thumbnail;<br \/>                InstagramMedia lowRes = post.Images.LowResolution;<br \/>                InstagramMedia stdRes = post.Images.StandardResolution;<br \/>            }<br \/> <br \/>            <span style=\"color: #008000\">\/\/ Video information<\/span><br \/>            <span style=\"color: #0000ff\">if<\/span> (post.Videos != <span style=\"color: #0000ff\">null<\/span>)<br \/>            {<br \/>                InstagramMedia lowBandwidth = post.Videos.LowBandwidth;<br \/>                InstagramMedia lowRes = post.Videos.LowResolution;<br \/>                InstagramMedia stdRes = post.Videos.StandardResolution;<br \/>            }<br \/> <br \/>            <span style=\"color: #008000\">\/\/ Get direct links and sizes of media<\/span><br \/>            Uri link = post.Link;<br \/>        }<br \/>    }<br \/>}<br \/><\/pre>\n<p><\/div>\n<h3>Receivers Behind Firewalls<\/h3>\n<p>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 &#8216;MS_WebHookDisableHttpsCheck&#8217; Application Setting to \u2018true\u2019. That is, if \u2018true\u2019 this will cause regular HTTP requests to go through. Obviously this setting should be used with caution!<\/p>\n<h3>WebHookManager Updates<\/h3>\n<p>We added a constructor for <a href=\"https:\/\/github.com\/aspnet\/\">WebHookManager<\/a> which enables wiring up the default <a href=\"https:\/\/github.com\/aspnet\/\">IWebHookManager<\/a> 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 <a href=\"http:\/\/autofac.org\/\">Autofac Dependency Injection<\/a> engine registering WebHookManager with a custom policy:<\/p>\n<div id=\"codeSnippetWrapper\">\n<pre id=\"codeSnippet\"><p><span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">static<\/span> <span style=\"color: #0000ff\">void<\/span> Register(HttpConfiguration config)<br \/>{<br \/>    <span style=\"color: #008000\">\/\/ Web API routes<\/span><br \/>    config.MapHttpAttributeRoutes();<br \/>    config.Routes.MapHttpRoute(<br \/>        name: <span style=\"color: #006080\">&quot;DefaultApi&quot;<\/span>,<br \/>        routeTemplate: <span style=\"color: #006080\">&quot;api\/{controller}\/{id}&quot;<\/span>,<br \/>        defaults: <span style=\"color: #0000ff\">new<\/span> { id = RouteParameter.Optional }<br \/>    );<br \/> <br \/>    <span style=\"color: #008000\">\/\/ Load basic support for sending WebHooks<\/span><br \/>    config.InitializeCustomWebHooks();<br \/> <br \/>    <span style=\"color: #008000\">\/\/ Load Azure Storage or SQL for persisting subscriptions<\/span><br \/>    config.InitializeCustomWebHooksAzureStorage();<br \/> <br \/>    <span style=\"color: #008000\">\/\/ Load Web API controllers for managing subscriptions<\/span><br \/>    config.InitializeCustomWebHooksApis();<br \/> <br \/>    <span style=\"color: #008000\">\/\/ Create custom WebHookManager with custom retry policy<\/span><br \/>    ILogger logger = config.DependencyResolver.GetLogger();<br \/>    IWebHookStore store = config.DependencyResolver.GetStore();<br \/>    IWebHookManager manager = <span style=\"color: #0000ff\">new<\/span> WebHookManager(store, logger, <span style=\"color: #0000ff\">new<\/span> TimeSpan[] { }, <span style=\"color: #0000ff\">null<\/span>);<br \/><br \/> <br \/>    <span style=\"color: #008000\">\/\/ Register WebHookManager with Autofac <\/span><br \/>    ContainerBuilder builder = <span style=\"color: #0000ff\">new<\/span> ContainerBuilder();<br \/>    builder.RegisterInstance(manager).As&lt;IWebHookManager&gt;().SingleInstance();<br \/> <br \/>    <span style=\"color: #008000\">\/\/ Register MVC and Web API controllers with Autofac<\/span><br \/>    Assembly currentAssembly = Assembly.GetExecutingAssembly();<br \/>    builder.RegisterApiControllers(currentAssembly);<br \/>    builder.RegisterControllers(currentAssembly);<br \/> <br \/>    <span style=\"color: #008000\">\/\/ Build the Autofac container and set it as the dependency resolver for both MVC and Web API<\/span><br \/>    IContainer container = builder.Build();<br \/>    DependencyResolver.SetResolver(<span style=\"color: #0000ff\">new<\/span> AutofacDependencyResolver(container));<br \/>    config.DependencyResolver = <span style=\"color: #0000ff\">new<\/span> AutofacWebApiDependencyResolver(container);<br \/>}<br \/><\/p><\/pre>\n<p><\/div>\n<p>We also added a new generic JSON WebHook receiver, but we will demonstrate that in a separate blog so stay tuned \ud83d\ude42<\/p>\n<p>Have fun and <a href=\"https:\/\/github.com\/aspnet\/webhooks\/issues\">keep the feedback coming<\/a>!<\/p>\n<p>Henrik<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 \u2013 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 [&hellip;]<\/p>\n","protected":false},"author":403,"featured_media":58792,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[197],"tags":[34,7505,7506],"class_list":["post-6031","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aspnet","tag-asp-net-web-api","tag-asp-net-webhooks","tag-webhooks"],"acf":[],"blog_post_summary":"<p>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 \u2013 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 [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/6031","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/403"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=6031"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/6031\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=6031"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=6031"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=6031"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}