From a2071a86dd380fadb267b2dcbaa449485fbf3f08 Mon Sep 17 00:00:00 2001
From: Necati Meral <necati_meral@yahoo.de>
Date: Fri, 22 Jan 2021 23:31:50 +0100
Subject: [PATCH 1/2] Added Microsoft.AspNetcore.WebHooks.Receivers.AzureDevOps

---
 src/WebHooks/WebHooks.sln                     |  22 ++-
 ...zureDevOpsStronglyTypedCoreReceiver.csproj |  11 ++
 .../Controllers/AzureDevOpsController.cs      |  35 +++++
 .../Program.cs                                |  17 +++
 .../Startup.cs                                |  25 ++++
 .../appsettings.json                          |  16 +++
 .../AzureDevOpsConstants.cs                   |  22 +++
 .../AzureDevOpsWebHookAttribute.cs            |  61 ++++++++
 .../BasePayload.cs                            |  81 +++++++++++
 .../BaseResource.cs                           |  13 ++
 .../BaseWorkItemResource.cs                   |  45 ++++++
 .../BuildCompletedDefinition.cs               |  50 +++++++
 .../BuildCompletedDrop.cs                     |  38 +++++
 .../BuildCompletedLog.cs                      |  32 +++++
 .../BuildCompletedPayload.cs                  |  12 ++
 .../BuildCompletedQueueDefinition.cs          |  38 +++++
 .../BuildCompletedRequest.cs                  |  32 +++++
 .../BuildCompletedResource.cs                 | 128 +++++++++++++++++
 .../CodeCheckedInPayload.cs                   |  12 ++
 .../CodeCheckedInResource.cs                  |  50 +++++++
 .../AzureDevOpsMvcBuilderExtensions.cs        |  43 ++++++
 .../AzureDevOpsMvcCoreBuilderExtensions.cs    |  45 ++++++
 .../AzureDevOpsServiceCollectionSetup.cs      |  28 ++++
 .../GitCommit.cs                              |  44 ++++++
 .../GitLink.cs                                |  20 +++
 .../GitMergeCommit.cs                         |  26 ++++
 .../GitProject.cs                             |  38 +++++
 .../GitPullLinks.cs                           |  67 +++++++++
 .../GitPullRequestCreatedPayload.cs           |  12 ++
 ...GitPullRequestMergeCommitCreatedPayload.cs |  12 ++
 ...itPullRequestMergeCommitCreatedResource.cs |  12 ++
 .../GitPullRequestResource.cs                 | 132 ++++++++++++++++++
 .../GitPullRequestUpdatedPayload.cs           |  12 ++
 .../GitPullRequestUpdatedResource.cs          |  20 +++
 .../GitPushLinks.cs                           |  43 ++++++
 .../GitPushPayload.cs                         |  12 ++
 .../GitPushResource.cs                        |  72 ++++++++++
 .../GitRefUpdate.cs                           |  31 ++++
 .../GitRepository.cs                          |  50 +++++++
 .../GitReviewer.cs                            |  32 +++++
 .../GitUser.cs                                |  44 ++++++
 .../GitUserInfo.cs                            |  32 +++++
 .../Metadata/AzureDevOpsMetadata.cs           |  35 +++++
 ...Core.WebHooks.Receivers.AzureDevOps.csproj |  17 +++
 .../PayloadMessage.cs                         |  31 ++++
 .../PayloadResourceContainer.cs               |  19 +++
 .../PayloadResourceContainers.cs              |  31 ++++
 .../Properties/Resources.Designer.cs          |  72 ++++++++++
 .../Properties/Resources.resx                 | 123 ++++++++++++++++
 .../ResourceUser.cs                           |  44 ++++++
 .../TeamRoomMessagePostedPayload.cs           |  12 ++
 .../TeamRoomMessagePostedResource.cs          |  50 +++++++
 .../WorkItemCommentedOnPayload.cs             |  12 ++
 .../WorkItemCommentedOnResource.cs            |  12 ++
 .../WorkItemCreatedPayload.cs                 |  12 ++
 .../WorkItemCreatedResource.cs                |  12 ++
 .../WorkItemDeletedPayload.cs                 |  12 ++
 .../WorkItemDeletedResource.cs                |  12 ++
 .../WorkItemFields.cs                         | 104 ++++++++++++++
 .../WorkItemLink.cs                           |  19 +++
 .../WorkItemLinks.cs                          |  61 ++++++++
 .../WorkItemRestoredPayload.cs                |  12 ++
 .../WorkItemRestoredResource.cs               |  12 ++
 .../WorkItemUpdatedFieldValue.cs              |  26 ++++
 .../WorkItemUpdatedFields.cs                  |  68 +++++++++
 .../WorkItemUpdatedPayload.cs                 |  12 ++
 .../WorkItemUpdatedResource.cs                |  38 +++++
 .../WorkItemUpdatedRevision.cs                |  38 +++++
 68 files changed, 2459 insertions(+), 4 deletions(-)
 create mode 100644 src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/AzureDevOpsStronglyTypedCoreReceiver.csproj
 create mode 100644 src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Controllers/AzureDevOpsController.cs
 create mode 100644 src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Program.cs
 create mode 100644 src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Startup.cs
 create mode 100644 src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/appsettings.json
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/AzureDevOpsConstants.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/AzureDevOpsWebHookAttribute.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BasePayload.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BaseResource.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BaseWorkItemResource.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedDefinition.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedDrop.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedLog.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedPayload.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedQueueDefinition.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedRequest.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedResource.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/CodeCheckedInPayload.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/CodeCheckedInResource.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Extensions/AzureDevOpsMvcBuilderExtensions.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Extensions/AzureDevOpsMvcCoreBuilderExtensions.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Extensions/AzureDevOpsServiceCollectionSetup.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitCommit.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitLink.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitMergeCommit.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitProject.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullLinks.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestCreatedPayload.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestMergeCommitCreatedPayload.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestMergeCommitCreatedResource.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestResource.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestUpdatedPayload.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestUpdatedResource.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPushLinks.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPushPayload.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPushResource.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitRefUpdate.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitRepository.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitReviewer.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitUser.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitUserInfo.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Metadata/AzureDevOpsMetadata.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps.csproj
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/PayloadMessage.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/PayloadResourceContainer.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/PayloadResourceContainers.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Properties/Resources.Designer.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Properties/Resources.resx
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/ResourceUser.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/TeamRoomMessagePostedPayload.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/TeamRoomMessagePostedResource.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemCommentedOnPayload.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemCommentedOnResource.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemCreatedPayload.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemCreatedResource.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemDeletedPayload.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemDeletedResource.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemFields.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemLink.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemLinks.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemRestoredPayload.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemRestoredResource.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedFieldValue.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedFields.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedPayload.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedResource.cs
 create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedRevision.cs

diff --git a/src/WebHooks/WebHooks.sln b/src/WebHooks/WebHooks.sln
index 6df629902..54467e146 100644
--- a/src/WebHooks/WebHooks.sln
+++ b/src/WebHooks/WebHooks.sln
@@ -1,7 +1,7 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27110.0
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30711.63
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Src", "Src", "{929F44D0-A040-4DC3-A22F-4C5829C05D44}"
 	ProjectSection(SolutionItems) = preProject
@@ -35,7 +35,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GitHubCoreReceiver", "sampl
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebHooks.Receivers.AzureAlert", "src\Microsoft.AspNetCore.WebHooks.Receivers.AzureAlert\Microsoft.AspNetCore.WebHooks.Receivers.AzureAlert.csproj", "{FAE4E7F8-7786-4388-802D-69C5C40DD5ED}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.WebHooks.Receivers.AzureContainerRegistry", "src\Microsoft.AspNetCore.WebHooks.Receivers.AzureContainerRegistry\Microsoft.AspNetCore.WebHooks.Receivers.AzureContainerRegistry.csproj", "{B4297872-1ED3-4A5D-95A8-0C1A11FDF781}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebHooks.Receivers.AzureContainerRegistry", "src\Microsoft.AspNetCore.WebHooks.Receivers.AzureContainerRegistry\Microsoft.AspNetCore.WebHooks.Receivers.AzureContainerRegistry.csproj", "{B4297872-1ED3-4A5D-95A8-0C1A11FDF781}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebHooks.Receivers.BitBucket", "src\Microsoft.AspNetCore.WebHooks.Receivers.BitBucket\Microsoft.AspNetCore.WebHooks.Receivers.BitBucket.csproj", "{06B0D9D1-1368-423E-B2F7-5F408423A187}"
 EndProject
@@ -99,6 +99,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TrelloCoreReceiver", "sampl
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebHooks.FunctionalTest", "test\Microsoft.AspNetCore.WebHooks.FunctionalTest\Microsoft.AspNetCore.WebHooks.FunctionalTest.csproj", "{F42E56B7-60D4-481A-8585-04015B2B501E}"
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps", "src\Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps\Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps.csproj", "{820D031D-237E-4892-A0BD-EF341421066A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureDevOpsStronglyTypedCoreReceiver", "samples\AzureDevOpstronglyTypedCoreReceiver\AzureDevOpsStronglyTypedCoreReceiver.csproj", "{DAE01DE1-421B-420C-87DE-74ED9279A034}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -249,6 +253,14 @@ Global
 		{F42E56B7-60D4-481A-8585-04015B2B501E}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{F42E56B7-60D4-481A-8585-04015B2B501E}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{F42E56B7-60D4-481A-8585-04015B2B501E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{820D031D-237E-4892-A0BD-EF341421066A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{820D031D-237E-4892-A0BD-EF341421066A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{820D031D-237E-4892-A0BD-EF341421066A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{820D031D-237E-4892-A0BD-EF341421066A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DAE01DE1-421B-420C-87DE-74ED9279A034}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DAE01DE1-421B-420C-87DE-74ED9279A034}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DAE01DE1-421B-420C-87DE-74ED9279A034}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DAE01DE1-421B-420C-87DE-74ED9279A034}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -290,9 +302,11 @@ Global
 		{91E02D64-BA6E-473C-A250-D1051A50DDAB} = {9575CB90-BC4B-43BB-8AEA-82C53FDA4187}
 		{E9E37253-3FE1-44A4-A9E7-A2B6C54EECFE} = {E957C8D9-B4A0-488B-838F-BAB4DE080A76}
 		{F42E56B7-60D4-481A-8585-04015B2B501E} = {9575CB90-BC4B-43BB-8AEA-82C53FDA4187}
+		{820D031D-237E-4892-A0BD-EF341421066A} = {929F44D0-A040-4DC3-A22F-4C5829C05D44}
+		{DAE01DE1-421B-420C-87DE-74ED9279A034} = {E957C8D9-B4A0-488B-838F-BAB4DE080A76}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
-		SolutionGuid = {12CE6238-F847-4984-8622-1ED46072150A}
 		EnterpriseLibraryConfigurationToolBinariesPathV6 = packages\EnterpriseLibrary.TransientFaultHandling.6.0.1304.0\lib\portable-net45+win+wp8;packages\EnterpriseLibrary.TransientFaultHandling.Data.6.0.1304.1\lib\NET45
+		SolutionGuid = {12CE6238-F847-4984-8622-1ED46072150A}
 	EndGlobalSection
 EndGlobal
diff --git a/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/AzureDevOpsStronglyTypedCoreReceiver.csproj b/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/AzureDevOpsStronglyTypedCoreReceiver.csproj
new file mode 100644
index 000000000..c8685dd78
--- /dev/null
+++ b/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/AzureDevOpsStronglyTypedCoreReceiver.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+  <PropertyGroup>
+    <TargetFrameworks>$(StandardTestWebsiteTfms)</TargetFrameworks>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore" Version="$(MicrosoftAspNetCorePackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Mvc.DataAnnotations" Version="$(MicrosoftAspNetCoreMvcDataAnnotationsPackageVersion)" />
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps\Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps.csproj" />
+  </ItemGroup>
+</Project>
diff --git a/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Controllers/AzureDevOpsController.cs b/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Controllers/AzureDevOpsController.cs
new file mode 100644
index 000000000..72f35313b
--- /dev/null
+++ b/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Controllers/AzureDevOpsController.cs
@@ -0,0 +1,35 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.WebHooks;
+using Microsoft.Extensions.Logging;
+using Newtonsoft.Json.Linq;
+
+namespace AzureDevOpsStronglyTypedCoreReceiver.Controllers
+{
+    public class AzureDevOpsController : ControllerBase
+    {
+        private readonly ILogger _logger;
+
+        public AzureDevOpsController(ILoggerFactory loggerFactory)
+        {
+            _logger = loggerFactory.CreateLogger<AzureDevOpsController>();
+        }
+
+        [AzureDevOpsWebHook]
+        public IActionResult AzureDevOps(string id, string @event, string webHookId, JObject data)
+        {
+            if (!ModelState.IsValid)
+            {
+                return BadRequest(ModelState);
+            }
+
+            _logger.LogInformation(
+                1,
+                $"{nameof(AzureDevOpsController)} / '{{Id}}' received '{{EventName}}' and '{{WebHookId}}'.",
+                id,
+                @event,
+                webHookId);
+
+            return Ok();
+        }
+    }
+}
diff --git a/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Program.cs b/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Program.cs
new file mode 100644
index 000000000..7e7296634
--- /dev/null
+++ b/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Program.cs
@@ -0,0 +1,17 @@
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+
+namespace AzureDevOpsStronglyTypedCoreReceiver
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            CreateWebHostBuilder(args).Build().Run();
+        }
+
+        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
+            WebHost.CreateDefaultBuilder(args)
+                .UseStartup<Startup>();
+    }
+}
diff --git a/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Startup.cs b/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Startup.cs
new file mode 100644
index 000000000..bc8f5527e
--- /dev/null
+++ b/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Startup.cs
@@ -0,0 +1,25 @@
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace AzureDevOpsStronglyTypedCoreReceiver
+{
+    public class Startup
+    {
+        // This method gets called by the runtime. Use this method to add services to the container.
+        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
+        public void ConfigureServices(IServiceCollection services)
+        {
+            services
+                .AddMvcCore()
+                .AddAzureDevOpsWebHooks()
+                .AddDataAnnotations();
+        }
+
+        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
+        {
+            app.UseMvc();
+        }
+    }
+}
diff --git a/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/appsettings.json b/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/appsettings.json
new file mode 100644
index 000000000..e5c9d1634
--- /dev/null
+++ b/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/appsettings.json
@@ -0,0 +1,16 @@
+{
+  "WebHooks:AzureDevOps:SecretKey:default": "01234567890123456789012345678901",
+  "Logging": {
+    "IncludeScopes": false,
+    "LogLevel": {
+      "Default": "Warning"
+    },
+    "Console": {
+      "LogLevel": {
+        "AzureDevOpsStronglyTypedCoreReceiver": "Information",
+        "Default": "Warning",
+        "Microsoft": "Information"
+      }
+    }
+  }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/AzureDevOpsConstants.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/AzureDevOpsConstants.cs
new file mode 100644
index 000000000..1e753b9dd
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/AzureDevOpsConstants.cs
@@ -0,0 +1,22 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Well-known names used in Azure DevOps receivers and handlers.
+    /// </summary>
+    public static class AzureDevOpsConstants
+    {
+        /// <summary>
+        /// Gets the JSON path of the property in an Azure DevOps WebHook request body containing the Azure DevOps event
+        /// type.
+        /// </summary>
+        public static string EventBodyPropertyPath => "$['eventType']";
+
+        /// <summary>
+        /// Gets the name of the Azure DevOps WebHook receiver.
+        /// </summary>
+        public static string ReceiverName => "azuredevops";
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/AzureDevOpsWebHookAttribute.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/AzureDevOpsWebHookAttribute.cs
new file mode 100644
index 000000000..13eef0629
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/AzureDevOpsWebHookAttribute.cs
@@ -0,0 +1,61 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Infrastructure;
+using Microsoft.AspNetCore.WebHooks.Filters;
+using Microsoft.AspNetCore.WebHooks.Metadata;
+using Microsoft.AspNetCore.WebHooks.Properties;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// <para>
+    /// An <see cref="Attribute"/> indicating the associated action is an Azure DevOps WebHook endpoint. Specifies the
+    /// optional <see cref="WebHookAttribute.Id"/>. Also adds a <see cref="WebHookReceiverExistsFilter"/> and a
+    /// <see cref="ModelStateInvalidFilter"/> (unless <see cref="ApiBehaviorOptions.SuppressModelStateInvalidFilter"/>
+    /// is <see langword="true"/>) for the action.
+    /// </para>
+    /// <para>
+    /// The signature of the action should be:
+    /// <code>
+    /// Task{IActionResult} ActionName(string id, string @event, TData data)
+    /// </code>
+    /// or include the subset of parameters required. <c>TData</c> must be compatible with expected requests e.g.
+    /// <see cref="Newtonsoft.Json.Linq.JObject"/> or <see cref="AzureDevOpsNotification"/>.
+    /// </para>
+    /// <para>
+    /// An example Azure DevOps WebHook URI is
+    /// '<c>https://{host}/api/webhooks/incoming/azuredevops/{id}?code=83699ec7c1d794c0c780e49a5c72972590571fd8</c>'.
+    /// See
+    /// <see href="https://docs.microsoft.com/en-us/azure/devops/service-hooks/services/webhooks?view=azure-devops"/>
+    /// for additional details about Azure DevOps WebHook requests.
+    /// </para>
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// If the application enables CORS in general (see the <c>Microsoft.AspNetCore.Cors</c> package), apply
+    /// <c>DisableCorsAttribute</c> to this action. If the application depends on the
+    /// <c>Microsoft.AspNetCore.Mvc.ViewFeatures</c> package, apply <c>IgnoreAntiforgeryTokenAttribute</c> to this
+    /// action.
+    /// </para>
+    /// <para>
+    /// <see cref="AzureDevOpsWebHookAttribute"/> should be used at most once per <see cref="WebHookAttribute.Id"/> and
+    /// <see cref="EventName"/> in a WebHook application.
+    /// </para>
+    /// </remarks>
+    public class AzureDevOpsWebHookAttribute : WebHookAttribute
+    {
+        private string _eventName;
+
+        /// <summary>
+        /// Instantiates a new <see cref="AzureDevOpsWebHookAttribute"/> indicating the associated action is an Azure
+        /// DevOps WebHook endpoint.
+        /// </summary>
+        public AzureDevOpsWebHookAttribute()
+            : base(AzureDevOpsConstants.ReceiverName)
+        {
+        }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BasePayload.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BasePayload.cs
new file mode 100644
index 000000000..6f23fdcd6
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BasePayload.cs
@@ -0,0 +1,81 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Root object of payload sent for all types of events.
+    /// </summary>
+    /// <typeparam name="T">Type of resource within payload which differs depending on '<c>eventType</c>' field</typeparam>
+    public abstract class BasePayload<T> where T : BaseResource
+    {
+        /// <summary>
+        /// Gets the subscription identifier which triggered the event.
+        /// </summary>
+        [JsonProperty("subscriptionId")]
+        public string SubscriptionId { get; set; }
+
+        /// <summary>
+        /// Gets the notification identifier within subscription.
+        /// </summary>
+        [JsonProperty("notificationId")]
+        public int NotificationId { get; set; }
+
+        /// <summary>
+        /// Gets the identifier of HTTP request.
+        /// </summary>
+        [JsonProperty("id")]
+        public string Id { get; set; }
+
+        /// <summary>
+        /// Gets the type of the event.
+        /// </summary>
+        [JsonProperty("eventType")]
+        public string EventType { get; set; }
+
+        /// <summary>
+        /// Gets the publisher identifier.
+        /// </summary>
+        [JsonProperty("publisherId")]
+        public string PublisherId { get; set; }
+
+        /// <summary>
+        /// Gets the message which describes the event.
+        /// </summary>
+        [JsonProperty("message")]
+        public PayloadMessage Message { get; set; }
+
+        /// <summary>
+        /// Gets the detailed message which describes the event.
+        /// </summary>
+        [JsonProperty("detailedMessage")]
+        public PayloadMessage DetailedMessage { get; set; }
+
+        /// <summary>
+        /// Gets the resource itself - data associated with corresponding event.
+        /// </summary>
+        [JsonProperty("resource")]
+        public T Resource { get; set; }
+
+        /// <summary>
+        /// Gets the resource version.
+        /// </summary>
+        [JsonProperty("resourceVersion")]
+        public string ResourceVersion { get; set; }
+
+        /// <summary>
+        /// Gets the resource containers.
+        /// </summary>
+        [JsonProperty("resourceContainers")]
+        public PayloadResourceContainers ResourceContainers { get; set; }
+
+        /// <summary>
+        /// Gets the date when HTTP request was created.
+        /// </summary>
+        [JsonProperty("createdDate")]
+        public DateTime CreatedDate { get; set; }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BaseResource.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BaseResource.cs
new file mode 100644
index 000000000..b446b9688
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BaseResource.cs
@@ -0,0 +1,13 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Base class for resource object which describes 
+    /// a specific event type.
+    /// </summary>
+    public abstract class BaseResource
+    {
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BaseWorkItemResource.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BaseWorkItemResource.cs
new file mode 100644
index 000000000..6b7a34681
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BaseWorkItemResource.cs
@@ -0,0 +1,45 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Base class for resource object which describes WorkItem event types.
+    /// </summary>
+    /// <typeparam name="T">Type which describes fields associated with this kind of WorkItem change</typeparam>
+    public abstract class BaseWorkItemResource<T> : BaseResource
+    {
+        /// <summary>
+        /// Gets the identifier of WorkItem.
+        /// </summary>
+        [JsonProperty("id")]
+        public int Id { get; set; }
+
+        /// <summary>
+        /// Gets the revision number.
+        /// </summary>
+        [JsonProperty("rev")]
+        public int RevisionNumber { get; set; }
+
+        /// <summary>
+        /// Gets fields associated with the WorkItem.
+        /// </summary>
+        [JsonProperty("fields")]
+        public T Fields { get; set; }
+
+        /// <summary>
+        /// Gets links associated with the WorkItem.
+        /// </summary>
+        [JsonProperty("_links")]
+        public WorkItemLinks Links { get; set; }
+
+        /// <summary>
+        /// Gets the URL of the WorkItem.
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+    }    
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedDefinition.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedDefinition.cs
new file mode 100644
index 000000000..6457d3314
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedDefinition.cs
@@ -0,0 +1,50 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes build definition
+    /// </summary>
+    public class BuildCompletedDefinition
+    {
+        /// <summary>
+        /// Gets the size of the batch.
+        /// </summary>
+        [JsonProperty("batchSize")]
+        public int BatchSize { get; set; }
+
+        /// <summary>
+        /// Gets the trigger type.
+        /// </summary>
+        [JsonProperty("triggerType")]
+        public string TriggerType { get; set; }
+
+        /// <summary>
+        /// Gets the trigger type.
+        /// </summary>
+        [JsonProperty("definitionType")]
+        public string DefinitionType { get; set; }
+
+        /// <summary>
+        /// Gets the identifier of the build definition.
+        /// </summary>
+        [JsonProperty("id")]
+        public int Id { get; set; }
+
+        /// <summary>
+        /// Gets the name of the build definition.
+        /// </summary>
+        [JsonProperty("name")]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// Gets the URL of the build definition.
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedDrop.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedDrop.cs
new file mode 100644
index 000000000..381f02625
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedDrop.cs
@@ -0,0 +1,38 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes build drop
+    /// </summary>
+    public class BuildCompletedDrop
+    {
+        /// <summary>
+        /// Gets drop location.
+        /// </summary>
+        [JsonProperty("location")]
+        public string Location { get; set; }
+
+        /// <summary>
+        /// Gets drop type.
+        /// </summary>
+        [JsonProperty("type")]
+        public string DropType { get; set; }
+
+        /// <summary>
+        /// Gets drop location URL.
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+
+        /// <summary>
+        /// Gets drop location download URL.
+        /// </summary>
+        [JsonProperty("downloadUrl")]
+        public Uri DownloadUrl { get; set; }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedLog.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedLog.cs
new file mode 100644
index 000000000..6ef1a24cc
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedLog.cs
@@ -0,0 +1,32 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes build log 
+    /// </summary>
+    public class BuildCompletedLog
+    {
+        /// <summary>
+        /// Gets the log type.
+        /// </summary>
+        [JsonProperty("type")]
+        public string LogType { get; set; }
+
+        /// <summary>
+        /// Gets the log URL.
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+
+        /// <summary>
+        /// Gets the log download URL.
+        /// </summary>
+        [JsonProperty("downloadUrl")]
+        public Uri DownloadUrl { get; set; }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedPayload.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedPayload.cs
new file mode 100644
index 000000000..80ec71c65
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedPayload.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the entire payload of event '<c>build.complete</c>'.
+    /// </summary>
+    public class BuildCompletedPayload : BasePayload<BuildCompletedResource>
+    {
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedQueueDefinition.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedQueueDefinition.cs
new file mode 100644
index 000000000..575aefe04
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedQueueDefinition.cs
@@ -0,0 +1,38 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the queue of the build.
+    /// </summary>
+    public class BuildCompletedQueueDefinition
+    {
+        /// <summary>
+        /// Gets the type of the queue.
+        /// </summary>
+        [JsonProperty("queueType")]
+        public string QueueType { get; set; }
+
+        /// <summary>
+        /// Gets the identifier of the queue.
+        /// </summary>
+        [JsonProperty("id")]
+        public int Id { get; set; }
+
+        /// <summary>
+        /// Gets the name of the queue.
+        /// </summary>
+        [JsonProperty("name")]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// Gets the URL of the queue.
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedRequest.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedRequest.cs
new file mode 100644
index 000000000..4e34c840a
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedRequest.cs
@@ -0,0 +1,32 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the request of the build.
+    /// </summary>
+    public class BuildCompletedRequest
+    {
+        /// <summary>
+        /// Gets the identifier of the request.
+        /// </summary>
+        [JsonProperty("id")]
+        public int Id { get; set; }
+
+        /// <summary>
+        /// Gets the URL of the request.
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+
+        /// <summary>
+        /// Gets the user associated with the request.
+        /// </summary>
+        [JsonProperty("requestedFor")]
+        public ResourceUser RequestedFor { get; set; }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedResource.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedResource.cs
new file mode 100644
index 000000000..6b270c805
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/BuildCompletedResource.cs
@@ -0,0 +1,128 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.ObjectModel;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the resource that associated with <see cref="BuildCompletedPayload"/>
+    /// </summary>
+    public class BuildCompletedResource : BaseResource
+    {
+        private readonly Collection<BuildCompletedRequest> _requests = new Collection<BuildCompletedRequest>();
+
+        /// <summary>
+        /// Gets the build URI.
+        /// </summary>
+        [JsonProperty("uri")]
+        public Uri Uri { get; set; }
+
+        /// <summary>
+        /// Gets the build identifier.
+        /// </summary>
+        [JsonProperty("id")]
+        public int Id { get; set; }
+
+        /// <summary>
+        /// Gets the build number.
+        /// </summary>
+        [JsonProperty("buildNumber")]
+        public string BuildNumber { get; set; }
+
+        /// <summary>
+        /// Gets the build URL.
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+
+        /// <summary>
+        /// Gets the start time of the build.
+        /// </summary>
+        [JsonProperty("startTime")]
+        public DateTime StartTime { get; set; }
+
+        /// <summary>
+        /// Gets the finish time of the build.
+        /// </summary>
+        [JsonProperty("finishTime")]
+        public DateTime FinishTime { get; set; }
+
+        /// <summary>
+        /// Gets the reason which triggered the build.
+        /// </summary>
+        [JsonProperty("reason")]
+        public string Reason { get; set; }
+
+        /// <summary>
+        /// Gets the outcome status of the build.
+        /// </summary>
+        [JsonProperty("status")]
+        public string Status { get; set; }
+
+        /// <summary>
+        /// Gets the build drop location.
+        /// </summary>
+        [JsonProperty("dropLocation")]
+        public string DropLocation { get; set; }
+
+        /// <summary>
+        /// Gets the build drop.
+        /// </summary>
+        [JsonProperty("drop")]
+        public BuildCompletedDrop Drop { get; set; }
+
+        /// <summary>
+        /// Gets the build log.
+        /// </summary>
+        [JsonProperty("log")]
+        public BuildCompletedLog Log { get; set; }
+
+        /// <summary>
+        /// Gets the source version for the build.
+        /// </summary>
+        [JsonProperty("sourceGetVersion")]
+        public string SourceGetVersion { get; set; }
+
+        /// <summary>
+        /// Gets the user which last changed the source.
+        /// </summary>
+        [JsonProperty("lastChangedBy")]
+        public ResourceUser LastChangedBy { get; set; }
+
+        /// <summary>
+        /// Gets value indicating whether this build retain indefinitely.
+        /// </summary>
+        [JsonProperty("retainIndefinitely")]
+        public bool RetainIndefinitely { get; set; }
+
+        /// <summary>
+        /// Gets value indicating whether this build has diagnostics.
+        /// </summary>
+        [JsonProperty("hasDiagnostics")]
+        public bool HasDiagnostics { get; set; }
+
+        /// <summary>
+        /// Gets the definition of the build.
+        /// </summary>
+        [JsonProperty("definition")]
+        public BuildCompletedDefinition Definition { get; set; }
+
+        /// <summary>
+        /// Gets the build queue.
+        /// </summary>
+        [JsonProperty("queue")]
+        public BuildCompletedQueueDefinition Queue { get; set; }
+
+        /// <summary>
+        /// Gets build requests.
+        /// </summary>
+        [JsonProperty("requests")]
+        public Collection<BuildCompletedRequest> Requests
+        {
+            get { return _requests; }
+        }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/CodeCheckedInPayload.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/CodeCheckedInPayload.cs
new file mode 100644
index 000000000..36786fea7
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/CodeCheckedInPayload.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the entire payload of event '<c>tfvc.checkin</c>'.
+    /// </summary>
+    public class CodeCheckedInPayload : BasePayload<CodeCheckedInResource>
+    {
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/CodeCheckedInResource.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/CodeCheckedInResource.cs
new file mode 100644
index 000000000..3e7b01ffb
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/CodeCheckedInResource.cs
@@ -0,0 +1,50 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the resource that associated with <see cref="CodeCheckedInPayload"/>
+    /// </summary>
+    public class CodeCheckedInResource : BaseResource
+    {
+        /// <summary>
+        /// Gets the changeset identifier.
+        /// </summary>
+        [JsonProperty("changesetId")]
+        public int ChangesetId { get; set; }
+
+        /// <summary>
+        /// Gets the changeset URL.
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+
+        /// <summary>
+        /// Gets the changeset author.
+        /// </summary>
+        [JsonProperty("author")]
+        public ResourceUser Author { get; set; }
+
+        /// <summary>
+        /// Gets the user that checked in the changeset.
+        /// </summary>
+        [JsonProperty("checkedInBy")]
+        public ResourceUser CheckedInBy { get; set; }
+
+        /// <summary>
+        /// Gets the changeset creation date.
+        /// </summary>
+        [JsonProperty("createdDate")]
+        public DateTime CreatedDate { get; set; }
+
+        /// <summary>
+        /// Gets the changeset comment.
+        /// </summary>
+        [JsonProperty("comment")]
+        public string Comment { get; set; }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Extensions/AzureDevOpsMvcBuilderExtensions.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Extensions/AzureDevOpsMvcBuilderExtensions.cs
new file mode 100644
index 000000000..349d9c999
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Extensions/AzureDevOpsMvcBuilderExtensions.cs
@@ -0,0 +1,43 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.ComponentModel;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+    /// <summary>
+    /// Extension methods for setting up Azure DevOps WebHooks in an <see cref="IMvcBuilder" />.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public static class AzureDevOpsMvcBuilderExtensions
+    {
+        /// <summary>
+        /// <para>
+        /// Add Azure DevOps WebHook configuration and services to the specified <paramref name="builder"/>. See
+        /// <see href="https://docs.microsoft.com/en-us/azure/devops/service-hooks/services/webhooks?view=azure-devops"/>
+        /// for additional details about Azure DevOps WebHook requests.
+        /// </para>
+        /// <para>
+        /// The '<c>WebHooks:AzureDevOps:SecretKey:default</c>' configuration value contains the secret key for Azure
+        /// DevOps WebHook URIs of the form '<c>https://{host}/api/webhooks/incoming/azuredevops?code={secret key}</c>'.
+        /// '<c>WebHooks:AzureDevOps:SecretKey:{id}</c>' configuration values contain secret keys for
+        /// Azure DevOps WebHook URIs of the form
+        /// '<c>https://{host}/api/webhooks/incoming/azuredevops/{id}?code={secret key}</c>'.
+        /// </para>
+        /// </summary>
+        /// <param name="builder">The <see cref="IMvcBuilder" /> to configure.</param>
+        /// <returns>The <paramref name="builder"/>.</returns>
+        public static IMvcBuilder AddAzureDevOpsWebHooks(this IMvcBuilder builder)
+        {
+            if (builder == null)
+            {
+                throw new ArgumentNullException(nameof(builder));
+            }
+
+            AzureDevOpsServiceCollectionSetup.AddAzureDevOpsServices(builder.Services);
+
+            return builder.AddWebHooks();
+        }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Extensions/AzureDevOpsMvcCoreBuilderExtensions.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Extensions/AzureDevOpsMvcCoreBuilderExtensions.cs
new file mode 100644
index 000000000..598efc55f
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Extensions/AzureDevOpsMvcCoreBuilderExtensions.cs
@@ -0,0 +1,45 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.ComponentModel;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+    /// <summary>
+    /// Extension methods for setting up Azure DevOps WebHooks in an <see cref="IMvcCoreBuilder" />.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public static class AzureDevOpsMvcCoreBuilderExtensions
+    {
+        /// <summary>
+        /// <para>
+        /// Add Azure DevOps WebHook configuration and services to the specified <paramref name="builder"/>. See
+        /// <see href="https://docs.microsoft.com/en-us/azure/devops/service-hooks/services/webhooks?view=azure-devops"/>
+        /// for additional details about Azure DevOps WebHook requests.
+        /// </para>
+        /// <para>
+        /// The '<c>WebHooks:AzureDevOps:SecretKey:default</c>' configuration value contains the secret key for Azure
+        /// DevOps WebHook URIs of the form '<c>https://{host}/api/webhooks/incoming/azureDevOps?code={secret key}</c>'.
+        /// '<c>WebHooks:AzureDevOps:SecretKey:{id}</c>' configuration values contain secret keys for
+        /// Azure DevOps WebHook URIs of the form
+        /// '<c>https://{host}/api/webhooks/incoming/azuredevops/{id}?code={secret key}</c>'.
+        /// </para>
+        /// </summary>
+        /// <param name="builder">The <see cref="IMvcCoreBuilder" /> to configure.</param>
+        /// <returns>The <paramref name="builder"/>.</returns>
+        public static IMvcCoreBuilder AddAzureDevOpsWebHooks(this IMvcCoreBuilder builder)
+        {
+            if (builder == null)
+            {
+                throw new ArgumentNullException(nameof(builder));
+            }
+
+            AzureDevOpsServiceCollectionSetup.AddAzureDevOpsServices(builder.Services);
+
+            return builder
+                .AddJsonFormatters()
+                .AddWebHooks();
+        }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Extensions/AzureDevOpsServiceCollectionSetup.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Extensions/AzureDevOpsServiceCollectionSetup.cs
new file mode 100644
index 000000000..120145003
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Extensions/AzureDevOpsServiceCollectionSetup.cs
@@ -0,0 +1,28 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Microsoft.AspNetCore.WebHooks.Metadata;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+    /// <summary>
+    /// Methods to add services for the Azure DevOps receiver.
+    /// </summary>
+    internal static class AzureDevOpsServiceCollectionSetup
+    {
+        /// <summary>
+        /// Add services for the Azure DevOps receiver.
+        /// </summary>
+        /// <param name="services">The <see cref="IServiceCollection"/> to update.</param>
+        public static void AddAzureDevOpsServices(IServiceCollection services)
+        {
+            if (services == null)
+            {
+                throw new ArgumentNullException(nameof(services));
+            }
+
+            WebHookMetadata.Register<AzureDevOpsMetadata>(services);
+        }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitCommit.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitCommit.cs
new file mode 100644
index 000000000..7c94ed127
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitCommit.cs
@@ -0,0 +1,44 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Contains information about the commit.
+    /// </summary>
+    public class GitCommit
+    {
+        /// <summary>
+        /// The Id of the commit.
+        /// </summary>
+        [JsonProperty("commitId")]
+        public string CommitId { get; set; }
+
+        /// <summary>
+        /// The user that authorized the commit.
+        /// </summary>
+        [JsonProperty("author")]
+        public GitUserInfo Author { get; set; }
+
+        /// <summary>
+        /// The user that committed the commit.
+        /// </summary>
+        [JsonProperty("committer")]
+        public GitUserInfo Committer { get; set; }
+
+        /// <summary>
+        /// The commit comment.
+        /// </summary>
+        [JsonProperty("comment")]
+        public string Comment { get; set; }
+
+        /// <summary>
+        /// The url of the commit.
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitLink.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitLink.cs
new file mode 100644
index 000000000..8eee22285
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitLink.cs
@@ -0,0 +1,20 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// The link.
+    /// </summary>
+    public class GitLink
+    {
+        /// <summary>
+        /// The url.
+        /// </summary>
+        [JsonProperty("href")]
+        public Uri Href { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitMergeCommit.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitMergeCommit.cs
new file mode 100644
index 000000000..e7f4bde8f
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitMergeCommit.cs
@@ -0,0 +1,26 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Merge Commit Information
+    /// </summary>
+    public class GitMergeCommit
+    {
+        /// <summary>
+        /// Commit Id
+        /// </summary>
+        [JsonProperty("commitId")]
+        public string CommitId { get; set; }
+
+        /// <summary>
+        /// Commit Url
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitProject.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitProject.cs
new file mode 100644
index 000000000..a8ee1688a
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitProject.cs
@@ -0,0 +1,38 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Information about a project.
+    /// </summary>
+    public class GitProject
+    {
+        /// <summary>
+        /// The project Id.
+        /// </summary>
+        [JsonProperty("id")]
+        public string Id { get; set; }
+
+        /// <summary>
+        /// The project name.
+        /// </summary>
+        [JsonProperty("name")]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// The url of the project.
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+
+        /// <summary>
+        /// The state of the project.
+        /// </summary>
+        [JsonProperty("state")]
+        public string State { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullLinks.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullLinks.cs
new file mode 100644
index 000000000..d49d1fb13
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullLinks.cs
@@ -0,0 +1,67 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Links for the Pull Request
+    /// </summary>
+    public class GitPullLinks
+    {
+        /// <summary>
+        /// Pull Request Link
+        /// </summary>
+        [JsonProperty("self")]
+        public GitLink Self { get; set; }
+
+        /// <summary>
+        /// Link to pull request web view
+        /// </summary>
+        [JsonProperty("web")]
+        public GitLink Web { get; set; }
+
+        /// <summary>
+        /// Repository Link
+        /// </summary>
+        [JsonProperty("repository")]
+        public GitLink Repository { get; set; }
+
+        /// <summary>
+        /// Link to Work Items
+        /// </summary>
+        [JsonProperty("workItems")]
+        public GitLink WorkItems { get; set; }
+
+        /// <summary>
+        /// Link to the Source Branch
+        /// </summary>
+        [JsonProperty("sourceBranch")]
+        public GitLink SourceBranch { get; set; }
+
+        /// <summary>
+        /// Link to the Target Branch
+        /// </summary>
+        [JsonProperty("targetBranch")]
+        public GitLink TargetBranch { get; set; }
+
+        /// <summary>
+        /// Link to the Source Commit
+        /// </summary>
+        [JsonProperty("sourceCommit")]
+        public GitLink SourceCommit { get; set; }
+
+        /// <summary>
+        /// Link to the Target Commit
+        /// </summary>
+        [JsonProperty("targetCommit")]
+        public GitLink TargetCommit { get; set; }
+
+        /// <summary>
+        /// Link to user that created the Commit
+        /// </summary>
+        [JsonProperty("createdBy")]
+        public GitLink CreatedBy { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestCreatedPayload.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestCreatedPayload.cs
new file mode 100644
index 000000000..acc9655f3
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestCreatedPayload.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Payload for the creation of a pull request
+    /// </summary>
+    public class GitPullRequestCreatedPayload : BasePayload<GitPullRequestResource>
+    {
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestMergeCommitCreatedPayload.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestMergeCommitCreatedPayload.cs
new file mode 100644
index 000000000..ec203f1cc
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestMergeCommitCreatedPayload.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Payload for the creation of a merge commit.
+    /// </summary>
+    public class GitPullRequestMergeCommitCreatedPayload : BasePayload<GitPullRequestMergeCommitCreatedResource>
+    {
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestMergeCommitCreatedResource.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestMergeCommitCreatedResource.cs
new file mode 100644
index 000000000..55b0e83b4
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestMergeCommitCreatedResource.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the resource that associated with <see cref="GitPullRequestMergeCommitCreatedPayload"/>
+    /// </summary>
+    public class GitPullRequestMergeCommitCreatedResource : GitPullRequestUpdatedResource
+    {
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestResource.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestResource.cs
new file mode 100644
index 000000000..576c1e150
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestResource.cs
@@ -0,0 +1,132 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.ObjectModel;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the resource that associated with <see cref="GitPullRequestCreatedPayload"/>
+    /// </summary>
+    public class GitPullRequestResource : BaseResource
+    {
+        private readonly Collection<GitReviewer> _reviewers = new Collection<GitReviewer>();
+        private readonly Collection<GitCommit> _commits = new Collection<GitCommit>();
+
+        /// <summary>
+        /// The repository being updated
+        /// </summary>
+        [JsonProperty("repository")]
+        public GitRepository Repository { get; set; }
+
+        /// <summary>
+        /// The Id of the Pull Request
+        /// </summary>
+        [JsonProperty("pullRequestId")]
+        public int PullRequestId { get; set; }
+
+        /// <summary>
+        /// The Status of the Pull Request
+        /// </summary>
+        [JsonProperty("status")]
+        public string Status { get; set; }
+
+        /// <summary>
+        /// The user creating the Pull Request
+        /// </summary>
+        [JsonProperty("createdBy")]
+        public GitUser CreatedBy { get; set; }
+
+        /// <summary>
+        /// The date the Pull Request was created.
+        /// </summary>
+        [JsonProperty("creationDate")]
+        public DateTime CreationDate { get; set; }
+
+        /// <summary>
+        /// The title of the Pull Request.
+        /// </summary>
+        [JsonProperty("title")]
+        public string Title { get; set; }
+
+        /// <summary>
+        /// The Description of the Pull Request
+        /// </summary>
+        [JsonProperty("description")]
+        public string Description { get; set; }
+
+        /// <summary>
+        /// Source Reference Name
+        /// </summary>
+        [JsonProperty("sourceRefName")]
+        public string SourceRefName { get; set; }
+
+        /// <summary>
+        /// Target Reference Name
+        /// </summary>
+        [JsonProperty("targetRefName")]
+        public string TargetRefName { get; set; }
+
+        /// <summary>
+        /// Merge Status
+        /// </summary>
+        [JsonProperty("mergeStatus")]
+        public string MergeStatus { get; set; }
+
+        /// <summary>
+        /// Merge Id
+        /// </summary>
+        [JsonProperty("mergeId")]
+        public string MergeId { get; set; }
+
+        /// <summary>
+        /// Last Merge Source Commit
+        /// </summary>
+        [JsonProperty("lastMergeSourceCommit")]
+        public GitMergeCommit LastMergeSourceCommit { get; set; }
+
+        /// <summary>
+        /// Last Merge Target Commit
+        /// </summary>
+        [JsonProperty("lastMergeTargetCommit")]
+        public GitMergeCommit LastMergeTargetCommit { get; set; }
+
+        /// <summary>
+        /// Last Merge Commit
+        /// </summary>
+        [JsonProperty("lastMergeCommit")]
+        public GitMergeCommit LastMergeCommit { get; set; }
+
+        /// <summary>
+        /// Pull Request Reviewers
+        /// </summary>
+        [JsonProperty("reviewers")]
+        public Collection<GitReviewer> Reviewers
+        {
+            get { return _reviewers; }
+        }
+
+        /// <summary>
+        /// Pull Request Url
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+
+        /// <summary>
+        /// Commit Links
+        /// </summary>
+        [JsonProperty("_links")]
+        public GitPullLinks Links { get; set; }
+
+        /// <summary>
+        /// A list of commits in the pull request
+        /// </summary>
+        [JsonProperty("commits")]
+        public Collection<GitCommit> Commits
+        {
+            get { return _commits; }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestUpdatedPayload.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestUpdatedPayload.cs
new file mode 100644
index 000000000..3eda577f7
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestUpdatedPayload.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Payload for the update of a pull request
+    /// </summary>
+    public class GitPullRequestUpdatedPayload : BasePayload<GitPullRequestUpdatedResource>
+    {
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestUpdatedResource.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestUpdatedResource.cs
new file mode 100644
index 000000000..ebe3df9ab
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPullRequestUpdatedResource.cs
@@ -0,0 +1,20 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the resource that associated with <see cref="GitPullRequestUpdatedPayload"/>
+    /// </summary>
+    public class GitPullRequestUpdatedResource : GitPullRequestResource
+    {
+        /// <summary>
+        /// The date the Pull Request was closed.
+        /// </summary>
+        [JsonProperty("closedDate")]
+        public DateTime ClosedDate { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPushLinks.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPushLinks.cs
new file mode 100644
index 000000000..4f8213892
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPushLinks.cs
@@ -0,0 +1,43 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// A collection of links about this push.
+    /// </summary>
+    public class GitPushLinks
+    {
+        /// <summary>
+        /// The link to the push.
+        /// </summary>
+        [JsonProperty("self")]
+        public GitLink Self { get; set; }
+
+        /// <summary>
+        /// The link to the repository.
+        /// </summary>
+        [JsonProperty("repository")]
+        public GitLink Repository { get; set; }
+
+        /// <summary>
+        /// The link to the commits.
+        /// </summary>
+        [JsonProperty("commits")]
+        public GitLink Commits { get; set; }
+
+        /// <summary>
+        /// The link to the user pushing the code.
+        /// </summary>
+        [JsonProperty("pusher")]
+        public GitLink Pusher { get; set; }
+
+        /// <summary>
+        /// The link to any references.
+        /// </summary>
+        [JsonProperty("refs")]
+        public GitLink Refs { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPushPayload.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPushPayload.cs
new file mode 100644
index 000000000..544882459
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPushPayload.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the entire payload of event '<c>git.push</c>'.
+    /// </summary>
+    public class GitPushPayload : BasePayload<GitPushResource>
+    {
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPushResource.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPushResource.cs
new file mode 100644
index 000000000..6632689b5
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitPushResource.cs
@@ -0,0 +1,72 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.ObjectModel;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the resource that associated with <see cref="GitPushPayload"/>
+    /// </summary>
+    public class GitPushResource : BaseResource
+    {
+        private readonly Collection<GitCommit> _commits = new Collection<GitCommit>();
+        private readonly Collection<GitRefUpdate> _refUpdates = new Collection<GitRefUpdate>();
+
+        /// <summary>
+        /// List of Commits in the push.
+        /// </summary>
+        [JsonProperty("commits")]
+        public Collection<GitCommit> Commits
+        {
+            get { return _commits; }
+        }
+
+        /// <summary>
+        /// List of Reference updates.
+        /// </summary>
+        [JsonProperty("refUpdates")]
+        public Collection<GitRefUpdate> RefUpdates
+        {
+            get { return _refUpdates; }
+        }
+
+        /// <summary>
+        /// The repository being updated
+        /// </summary>
+        [JsonProperty("repository")]
+        public GitRepository Repository { get; set; }
+
+        /// <summary>
+        /// The user pushing the code.
+        /// </summary>
+        [JsonProperty("pushedBy")]
+        public GitUser PushedBy { get; set; }
+
+        /// <summary>
+        /// The Id of the push.
+        /// </summary>
+        [JsonProperty("pushId")]
+        public int PushId { get; set; }
+
+        /// <summary>
+        /// The date of the push.
+        /// </summary>
+        [JsonProperty("date")]
+        public DateTime Date { get; set; }
+
+        /// <summary>
+        /// The Url of the push.
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+
+        /// <summary>
+        /// Links for the push
+        /// </summary>
+        [JsonProperty("_links")]
+        public GitPushLinks Links { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitRefUpdate.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitRefUpdate.cs
new file mode 100644
index 000000000..20222e87f
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitRefUpdate.cs
@@ -0,0 +1,31 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Information about the references.
+    /// </summary>
+    public class GitRefUpdate
+    {
+        /// <summary>
+        /// The name of the reference.
+        /// </summary>
+        [JsonProperty("name")]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// The old object Id.
+        /// </summary>
+        [JsonProperty("oldObjectId")]
+        public string OldObjectId { get; set; }
+
+        /// <summary>
+        /// The new object Id.
+        /// </summary>
+        [JsonProperty("newObjectId")]
+        public string NewObjectId { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitRepository.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitRepository.cs
new file mode 100644
index 000000000..487574cc8
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitRepository.cs
@@ -0,0 +1,50 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Repository information.
+    /// </summary>
+    public class GitRepository
+    {
+        /// <summary>
+        /// The Repository Id
+        /// </summary>
+        [JsonProperty("id")]
+        public string Id { get; set; }
+
+        /// <summary>
+        /// The Repository name.
+        /// </summary>
+        [JsonProperty("name")]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// The Repository Url.
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+
+        /// <summary>
+        /// The project.
+        /// </summary>
+        [JsonProperty("project")]
+        public GitProject Project { get; set; }
+
+        /// <summary>
+        /// The name of the default branch.
+        /// </summary>
+        [JsonProperty("defaultBranch")]
+        public string DefaultBranch { get; set; }
+
+        /// <summary>
+        /// The remote Url.
+        /// </summary>
+        [JsonProperty("remoteUrl")]
+        public Uri RemoteUrl { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitReviewer.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitReviewer.cs
new file mode 100644
index 000000000..2bd9b21f7
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitReviewer.cs
@@ -0,0 +1,32 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Information on a reviewer of a Pull Request.  Extends <see cref="GitUser"/>
+    /// </summary>
+    public class GitReviewer : GitUser
+    {
+        /// <summary>
+        /// Url of reviewer.
+        /// </summary>
+        [JsonProperty("reviewerUrl")]
+        public Uri ReviewerUrl { get; set; }
+
+        /// <summary>
+        /// The Reviewer's Vote
+        /// </summary>
+        [JsonProperty("vote")]
+        public int Vote { get; set; }
+
+        /// <summary>
+        /// Is Container
+        /// </summary>
+        [JsonProperty("isContainer")]
+        public bool IsContainer { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitUser.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitUser.cs
new file mode 100644
index 000000000..96b5bcb7c
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitUser.cs
@@ -0,0 +1,44 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Information about the git user.
+    /// </summary>
+    public class GitUser
+    {
+        /// <summary>
+        /// The git user Id.
+        /// </summary>
+        [JsonProperty("id")]
+        public string Id { get; set; }
+
+        /// <summary>
+        /// The git user display name.
+        /// </summary>
+        [JsonProperty("displayName")]
+        public string DisplayName { get; set; }
+
+        /// <summary>
+        /// The git user unique name.
+        /// </summary>
+        [JsonProperty("uniqueName")]
+        public string UniqueName { get; set; }
+
+        /// <summary>
+        /// The git user url.
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+
+        /// <summary>
+        /// The git user's image url.
+        /// </summary>
+        [JsonProperty("imageUrl")]
+        public Uri ImageUrl { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitUserInfo.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitUserInfo.cs
new file mode 100644
index 000000000..5f9766a3f
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/GitUserInfo.cs
@@ -0,0 +1,32 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Display information about a git user
+    /// </summary>
+    public class GitUserInfo
+    {
+        /// <summary>
+        /// Name of the user
+        /// </summary>
+        [JsonProperty("name")]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// Email of the user.
+        /// </summary>
+        [JsonProperty("email")]
+        public string Email { get; set; }
+
+        /// <summary>
+        /// A date associated with the user.
+        /// </summary>
+        [JsonProperty("date")]
+        public DateTime Date { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Metadata/AzureDevOpsMetadata.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Metadata/AzureDevOpsMetadata.cs
new file mode 100644
index 000000000..c9d6f3e39
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Metadata/AzureDevOpsMetadata.cs
@@ -0,0 +1,35 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks.Metadata
+{
+    /// <summary>
+    /// An <see cref="IWebHookMetadata"/> service containing metadata about the Azure Alert receiver.
+    /// </summary>
+    public class AzureDevOpsMetadata :
+        WebHookMetadata,
+        IWebHookEventFromBodyMetadata,
+        IWebHookVerifyCodeMetadata
+    {
+        /// <summary>
+        /// Instantiates a new <see cref="AzureDevOpsMetadata"/> instance.
+        /// </summary>
+        public AzureDevOpsMetadata()
+            : base(AzureDevOpsConstants.ReceiverName)
+        {
+        }
+
+        // IWebHookBodyTypeMetadataService...
+
+        /// <inheritdoc />
+        public override WebHookBodyType BodyType => WebHookBodyType.Json;
+
+        // IWebHookEventFromBodyMetadata...
+
+        /// <inheritdoc />
+        public bool AllowMissing => false;
+
+        /// <inheritdoc />
+        public string BodyPropertyPath => AzureDevOpsConstants.EventBodyPropertyPath;
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps.csproj b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps.csproj
new file mode 100644
index 000000000..f7b04bbb8
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps.csproj
@@ -0,0 +1,17 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <Description>ASP.NET Core Azure DevOps WebHooks infrastructure. Contains the AzureDevOpsWebHookAttribute class and AddAzureDevOpsWebHooks method.</Description>
+    <PackageTags>aspnetcore;webhook;receiver;azurealert</PackageTags>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Mvc.Formatters.Json" Version="$(MicrosoftAspNetCoreMvcFormattersJsonPackageVersion)" />
+    <ProjectReference Include="..\Microsoft.AspNetCore.WebHooks.Receivers\Microsoft.AspNetCore.WebHooks.Receivers.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Compile Update="Properties\Resources.Designer.cs">
+      <DesignTime>True</DesignTime>
+    </Compile>
+  </ItemGroup>
+</Project>
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/PayloadMessage.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/PayloadMessage.cs
new file mode 100644
index 000000000..581a5cb5e
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/PayloadMessage.cs
@@ -0,0 +1,31 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes payload message.
+    /// </summary>
+    public class PayloadMessage
+    {
+        /// <summary>
+        /// Gets the message in plain text.
+        /// </summary>
+        [JsonProperty("text")]
+        public string Text { get; set; }
+
+        /// <summary>
+        /// Gets the message in HTML format.
+        /// </summary>
+        [JsonProperty("html")]
+        public string Html { get; set; }
+
+        /// <summary>
+        /// Gets the message in markdown format.
+        /// </summary>
+        [JsonProperty("markdown")]
+        public string Markdown { get; set; }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/PayloadResourceContainer.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/PayloadResourceContainer.cs
new file mode 100644
index 000000000..43a46e377
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/PayloadResourceContainer.cs
@@ -0,0 +1,19 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes container
+    /// </summary>
+    public class PayloadResourceContainer
+    {
+        /// <summary>
+        /// Gets the identifier of container.
+        /// </summary>
+        [JsonProperty("id")]
+        public string Id { get; set; }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/PayloadResourceContainers.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/PayloadResourceContainers.cs
new file mode 100644
index 000000000..2d09565c0
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/PayloadResourceContainers.cs
@@ -0,0 +1,31 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes containers containing the resource
+    /// </summary>
+    public class PayloadResourceContainers
+    {
+        /// <summary>
+        /// Gets the collection.
+        /// </summary>
+        [JsonProperty("collection")]
+        public PayloadResourceContainer Collection { get; set; }
+
+        /// <summary>
+        /// Gets the account.
+        /// </summary>
+        [JsonProperty("account")]
+        public PayloadResourceContainer Account { get; set; }
+
+        /// <summary>
+        /// Gets the project.
+        /// </summary>
+        [JsonProperty("project")]
+        public PayloadResourceContainer Project { get; set; }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Properties/Resources.Designer.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Properties/Resources.Designer.cs
new file mode 100644
index 000000000..2655535d5
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Properties/Resources.Designer.cs
@@ -0,0 +1,72 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     Dieser Code wurde von einem Tool generiert.
+//     Laufzeitversion:4.0.30319.42000
+//
+//     Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
+//     der Code erneut generiert wird.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Microsoft.AspNetCore.WebHooks.Properties {
+    using System;
+    
+    
+    /// <summary>
+    ///   Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
+    /// </summary>
+    // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
+    // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
+    // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
+    // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.AspNetCore.WebHooks.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
+        ///   Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Sucht eine lokalisierte Zeichenfolge, die Value cannot be null or empty. ähnelt.
+        /// </summary>
+        internal static string General_ArgumentCannotBeNullOrEmpty {
+            get {
+                return ResourceManager.GetString("General_ArgumentCannotBeNullOrEmpty", resourceCulture);
+            }
+        }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Properties/Resources.resx b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Properties/Resources.resx
new file mode 100644
index 000000000..fd709f66a
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/Properties/Resources.resx
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="General_ArgumentCannotBeNullOrEmpty" xml:space="preserve">
+    <value>Value cannot be null or empty.</value>
+  </data>
+</root>
\ No newline at end of file
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/ResourceUser.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/ResourceUser.cs
new file mode 100644
index 000000000..6e7315553
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/ResourceUser.cs
@@ -0,0 +1,44 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes user entity
+    /// </summary>
+    public class ResourceUser
+    {
+        /// <summary>
+        /// Gets the identifier of the user.
+        /// </summary>
+        [JsonProperty("id")]
+        public string Id { get; set; }
+
+        /// <summary>
+        /// Gets the user display name.
+        /// </summary>
+        [JsonProperty("displayName")]
+        public string DisplayName { get; set; }
+
+        /// <summary>
+        /// Gets the user unique name.
+        /// </summary>
+        [JsonProperty("uniqueName")]
+        public string UniqueName { get; set; }
+
+        /// <summary>
+        /// Gets the user URL.
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+
+        /// <summary>
+        /// Gets the user image URL.
+        /// </summary>
+        [JsonProperty("imageUrl")]
+        public Uri ImageUrl { get; set; }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/TeamRoomMessagePostedPayload.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/TeamRoomMessagePostedPayload.cs
new file mode 100644
index 000000000..aad4eb0b0
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/TeamRoomMessagePostedPayload.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the entire payload of event '<c>message.posted</c>'.
+    /// </summary>
+    public class TeamRoomMessagePostedPayload : BasePayload<TeamRoomMessagePostedResource>
+    {
+    }    
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/TeamRoomMessagePostedResource.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/TeamRoomMessagePostedResource.cs
new file mode 100644
index 000000000..3ac0994f0
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/TeamRoomMessagePostedResource.cs
@@ -0,0 +1,50 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the resource that associated with <see cref="TeamRoomMessagePostedPayload"/>
+    /// </summary>
+    public class TeamRoomMessagePostedResource : BaseResource
+    {
+        /// <summary>
+        /// Gets the identifier.
+        /// </summary>
+        [JsonProperty("id")]
+        public int Id { get; set; }
+
+        /// <summary>
+        /// Gets the content of the message.
+        /// </summary>
+        [JsonProperty("content")]
+        public string Content { get; set; }
+
+        /// <summary>
+        /// Gets the type of the message.
+        /// </summary>
+        [JsonProperty("messageType")]
+        public string MessageType { get; set; }
+
+        /// <summary>
+        /// Gets the posted time of the message.
+        /// </summary>
+        [JsonProperty("postedTime")]
+        public DateTime PostedTime { get; set; }
+
+        /// <summary>
+        /// Gets the room identifier where message was posted.
+        /// </summary>
+        [JsonProperty("postedRoomId")]
+        public int PostedRoomId { get; set; }
+
+        /// <summary>
+        /// Gets the user who posted the message.
+        /// </summary>
+        [JsonProperty("postedBy")]
+        public ResourceUser PostedBy { get; set; }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemCommentedOnPayload.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemCommentedOnPayload.cs
new file mode 100644
index 000000000..7a7bea819
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemCommentedOnPayload.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the entire payload of event '<c>workitem.commented</c>'.
+    /// </summary>
+    public class WorkItemCommentedOnPayload : BasePayload<WorkItemCommentedOnResource>
+    {        
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemCommentedOnResource.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemCommentedOnResource.cs
new file mode 100644
index 000000000..572b3e33e
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemCommentedOnResource.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the resource that associated with <see cref="WorkItemCommentedOnPayload"/>
+    /// </summary>
+    public class WorkItemCommentedOnResource : BaseWorkItemResource<WorkItemFields>
+    {
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemCreatedPayload.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemCreatedPayload.cs
new file mode 100644
index 000000000..2491ca6c2
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemCreatedPayload.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the entire payload of event '<c>workitem.created</c>'.
+    /// </summary>
+    public class WorkItemCreatedPayload : BasePayload<WorkItemCreatedResource>
+    {        
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemCreatedResource.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemCreatedResource.cs
new file mode 100644
index 000000000..acab3d240
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemCreatedResource.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the resource that associated with <see cref="WorkItemCreatedPayload"/>
+    /// </summary>
+    public class WorkItemCreatedResource : BaseWorkItemResource<WorkItemFields>
+    {
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemDeletedPayload.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemDeletedPayload.cs
new file mode 100644
index 000000000..81d090d29
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemDeletedPayload.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the entire payload of event '<c>workitem.deleted</c>'.
+    /// </summary>
+    public class WorkItemDeletedPayload : BasePayload<WorkItemDeletedResource>
+    {
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemDeletedResource.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemDeletedResource.cs
new file mode 100644
index 000000000..01c65c3b9
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemDeletedResource.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the resource that associated with <see cref="WorkItemDeletedPayload"/>
+    /// </summary>
+    public class WorkItemDeletedResource : BaseWorkItemResource<WorkItemFields>
+    {
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemFields.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemFields.cs
new file mode 100644
index 000000000..f82bb98a7
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemFields.cs
@@ -0,0 +1,104 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes fields of the WorkItem
+    /// </summary>
+    public class WorkItemFields
+    {
+        /// <summary>
+        /// Gets the value of field <c>System.AreaPath</c>.
+        /// </summary>
+        [JsonProperty("System.AreaPath")]
+        public string SystemAreaPath { get; set; }
+
+        /// <summary>
+        /// Gets the value of field <c>System.TeamProject</c>.
+        /// </summary>
+        [JsonProperty("System.TeamProject")]
+        public string SystemTeamProject { get; set; }
+
+        /// <summary>
+        /// Gets the value of field <c>System.IterationPath</c>.
+        /// </summary>
+        [JsonProperty("System.IterationPath")]
+        public string SystemIterationPath { get; set; }
+
+        /// <summary>
+        /// Gets the value of field <c>System.WorkItemType</c>.
+        /// </summary>
+        [JsonProperty("System.WorkItemType")]
+        public string SystemWorkItemType { get; set; }
+
+        /// <summary>
+        /// Gets the value of field <c>System.State</c>.
+        /// </summary>
+        [JsonProperty("System.State")]
+        public string SystemState { get; set; }
+
+        /// <summary>
+        /// Gets the value of field <c>System.Reason</c>.
+        /// </summary>
+        [JsonProperty("System.Reason")]
+        public string SystemReason { get; set; }
+
+        /// <summary>
+        /// Gets the value of field <c>System.AssignedTo</c>.
+        /// </summary>
+        [JsonProperty("System.AssignedTo")]
+        public string SystemAssignedTo { get; set; }
+        
+        /// <summary>
+        /// Gets the value of field <c>System.CreatedDate</c>.
+        /// </summary>
+        [JsonProperty("System.CreatedDate")]
+        public DateTime SystemCreatedDate { get; set; }
+
+        /// <summary>
+        /// Gets the value of field <c>System.CreatedBy</c>.
+        /// </summary>
+        [JsonProperty("System.CreatedBy")]
+        public string SystemCreatedBy { get; set; }
+
+        /// <summary>
+        /// Gets the value of field <c>System.ChangedDate</c>.
+        /// </summary>
+        [JsonProperty("System.ChangedDate")]
+        public DateTime SystemChangedDate { get; set; }
+
+        /// <summary>
+        /// Gets the value of field <c>System.ChangedBy</c>.
+        /// </summary>
+        [JsonProperty("System.ChangedBy")]
+        public string SystemChangedBy { get; set; }
+
+        /// <summary>
+        /// Gets the value of field <c>System.Title</c>.
+        /// </summary>
+        [JsonProperty("System.Title")]
+        public string SystemTitle { get; set; }
+
+        /// <summary>
+        /// Gets the value of field <c>Microsoft.VSTS.Common.Severity</c>.
+        /// </summary>
+        [JsonProperty("Microsoft.VSTS.Common.Severity")]
+        public string MicrosoftCommonSeverity { get; set; }
+
+        /// <summary>
+        /// Gets the value of field <c>WEF_EB329F44FE5F4A94ACB1DA153FDF38BA_Kanban.Column</c>.
+        /// </summary>
+        [JsonProperty("WEF_EB329F44FE5F4A94ACB1DA153FDF38BA_Kanban.Column")]
+        public string KanbanColumn { get; set; }
+
+        /// <summary>
+        /// Gets the value of field <c>System.History</c>.
+        /// </summary>
+        [JsonProperty("System.History")]
+        public string SystemHistory { get; set; }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemLink.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemLink.cs
new file mode 100644
index 000000000..48e02a5d6
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemLink.cs
@@ -0,0 +1,19 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the WorkItem's link.
+    /// </summary>
+    public class WorkItemLink
+    {
+        /// <summary>
+        /// Gets the URL of WorkItem's link.
+        /// </summary>
+        [JsonProperty("href")]
+        public string Href { get; set; }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemLinks.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemLinks.cs
new file mode 100644
index 000000000..ae227ebae
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemLinks.cs
@@ -0,0 +1,61 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes links of the WorkItem.
+    /// </summary>
+    public class WorkItemLinks
+    {
+        /// <summary>
+        /// Gets the link to the WorkItem itself.
+        /// </summary>
+        [JsonProperty("self")]
+        public WorkItemLink Self { get; set; }
+
+        /// <summary>
+        /// Gets the link to the parent WorkItem if exists.
+        /// </summary>
+        [JsonProperty("parent")]
+        public WorkItemLink Parent { get; set; }
+
+        /// <summary>
+        /// Gets the link to the WorkItem' updates.
+        /// </summary>
+        [JsonProperty("workItemUpdates")]
+        public WorkItemLink WorkItemUpdates { get; set; }
+
+        /// <summary>
+        /// Gets the link to the WorkItem's revisions.
+        /// </summary>
+        [JsonProperty("workItemRevisions")]
+        public WorkItemLink WorkItemRevisions { get; set; }
+
+        /// <summary>
+        /// Gets the link to the WorkItem's type.
+        /// </summary>
+        [JsonProperty("workItemType")]
+        public WorkItemLink WorkItemType { get; set; }
+
+        /// <summary>
+        /// Gets the link to the WorkItem's fields.
+        /// </summary>
+        [JsonProperty("fields")]
+        public WorkItemLink Fields { get; set; }
+
+        /// <summary>
+        /// Gets the link to the WorkItem's HTML.
+        /// </summary>
+        [JsonProperty("html")]
+        public WorkItemLink Html { get; set; }
+
+        /// <summary>
+        /// Gets the link to the WorkItem's history.
+        /// </summary>
+        [JsonProperty("workItemHistory")]
+        public WorkItemLink WorkItemHistory { get; set; }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemRestoredPayload.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemRestoredPayload.cs
new file mode 100644
index 000000000..3a012a71d
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemRestoredPayload.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the entire payload of event '<c>workitem.restored</c>'.
+    /// </summary>
+    public class WorkItemRestoredPayload : BasePayload<WorkItemRestoredResource>
+    {        
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemRestoredResource.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemRestoredResource.cs
new file mode 100644
index 000000000..0fc77ff0c
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemRestoredResource.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the resource that associated with <see cref="WorkItemRestoredPayload"/>
+    /// </summary>
+    public class WorkItemRestoredResource : BaseWorkItemResource<WorkItemFields>
+    {
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedFieldValue.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedFieldValue.cs
new file mode 100644
index 000000000..85dc7432d
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedFieldValue.cs
@@ -0,0 +1,26 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes change of specific field
+    /// </summary>
+    /// <typeparam name="T">The string-type of the field that is being changed</typeparam>
+    public class WorkItemUpdatedFieldValue<T>
+    {
+        /// <summary>
+        /// Gets the value of the field before the change.
+        /// </summary>
+        [JsonProperty("oldValue")]
+        public T OldValue { get; set; }
+
+        /// <summary>
+        /// Gets the value of the field after the change.
+        /// </summary>
+        [JsonProperty("newValue")]
+        public T NewValue { get; set; }
+    }
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedFields.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedFields.cs
new file mode 100644
index 000000000..cc169c775
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedFields.cs
@@ -0,0 +1,68 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes fields of the WorkItem that was updated
+    /// </summary>
+    public class WorkItemUpdatedFields
+    {
+        /// <summary>
+        /// Gets the change information for the field '<c>System.Rev</c>'.
+        /// </summary>
+        [JsonProperty("System.Rev")]
+        public WorkItemUpdatedFieldValue<string> SystemRev { get; set; }
+
+        /// <summary>
+        /// Gets the change information for the field '<c>System.AuthorizedDate</c>'.
+        /// </summary>
+        [JsonProperty("System.AuthorizedDate")]
+        public WorkItemUpdatedFieldValue<DateTime> SystemAuthorizedDate { get; set; }
+
+        /// <summary>
+        /// Gets the change information for the field '<c>System.RevisedDate</c>'.
+        /// </summary>
+        [JsonProperty("System.RevisedDate")]
+        public WorkItemUpdatedFieldValue<DateTime> SystemRevisedDate { get; set; }
+
+        /// <summary>
+        /// Gets the change information for the field '<c>System.State</c>'.
+        /// </summary>
+        [JsonProperty("System.State")]
+        public WorkItemUpdatedFieldValue<string> SystemState { get; set; }
+
+        /// <summary>
+        /// Gets the change information for the field '<c>System.Reason</c>'.
+        /// </summary>
+        [JsonProperty("System.Reason")]
+        public WorkItemUpdatedFieldValue<string> SystemReason { get; set; }
+
+        /// <summary>
+        /// Gets the change information for the field '<c>System.AssignedTo</c>'.
+        /// </summary>
+        [JsonProperty("System.AssignedTo")]
+        public WorkItemUpdatedFieldValue<string> SystemAssignedTo { get; set; }
+
+        /// <summary>
+        /// Gets the change information for the field '<c>System.ChangedDate</c>'.
+        /// </summary>
+        [JsonProperty("System.ChangedDate")]
+        public WorkItemUpdatedFieldValue<DateTime> SystemChangedDate { get; set; }
+
+        /// <summary>
+        /// Gets the change information for the field '<c>System.Watermark</c>'.
+        /// </summary>
+        [JsonProperty("System.Watermark")]
+        public WorkItemUpdatedFieldValue<string> SystemWatermark { get; set; }
+
+        /// <summary>
+        /// Gets the change information for the field '<c>Microsoft.VSTS.Common.Severity</c>'.
+        /// </summary>
+        [JsonProperty("Microsoft.Vsts.Common.Severity")]
+        public WorkItemUpdatedFieldValue<string> MicrosoftCommonSeverity { get; set; }
+    }    
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedPayload.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedPayload.cs
new file mode 100644
index 000000000..014ac7148
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedPayload.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the entire payload of event '<c>workitem.updated</c>'.
+    /// </summary>
+    public class WorkItemUpdatedPayload : BasePayload<WorkItemUpdatedResource>
+    {        
+    }    
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedResource.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedResource.cs
new file mode 100644
index 000000000..96dbacd1e
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedResource.cs
@@ -0,0 +1,38 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the resource that associated with <see cref="WorkItemUpdatedPayload"/>
+    /// </summary>
+    public class WorkItemUpdatedResource : BaseWorkItemResource<WorkItemUpdatedFields>
+    {
+        /// <summary>
+        /// Gets WorkItem identifier.
+        /// </summary>
+        [JsonProperty("workItemId")]
+        public int WorkItemId { get; set; }
+
+        /// <summary>
+        /// Gets the author of revision.
+        /// </summary>
+        [JsonProperty("revisedBy")]
+        public ResourceUser RevisedBy { get; set; }
+
+        /// <summary>
+        /// Gets the revised date.
+        /// </summary>
+        [JsonProperty("revisedDate")]
+        public DateTime RevisedDate { get; set; }
+
+        /// <summary>
+        /// Gets the revision.
+        /// </summary>
+        [JsonProperty("revision")]
+        public WorkItemUpdatedRevision Revision { get; set; }
+    }    
+}
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedRevision.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedRevision.cs
new file mode 100644
index 000000000..731cd3594
--- /dev/null
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/WorkItemUpdatedRevision.cs
@@ -0,0 +1,38 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Newtonsoft.Json;
+
+namespace Microsoft.AspNetCore.WebHooks
+{
+    /// <summary>
+    /// Describes the revision
+    /// </summary>
+    public class WorkItemUpdatedRevision
+    {
+        /// <summary>
+        /// Gets the identifier of the revision.
+        /// </summary>
+        [JsonProperty("id")]
+        public int Id { get; set; }
+
+        /// <summary>
+        /// Gets the revision number.
+        /// </summary>
+        [JsonProperty("rev")]
+        public int Rev { get; set; }
+
+        /// <summary>
+        /// Gets the revision fields.
+        /// </summary>
+        [JsonProperty("fields")]
+        public WorkItemFields Fields { get; set; }
+
+        /// <summary>
+        /// Gets the revision URL.
+        /// </summary>
+        [JsonProperty("url")]
+        public Uri Url { get; set; }
+    }
+}

From 204b2cfe0d991b3b1f64679c26850408ccaca415 Mon Sep 17 00:00:00 2001
From: Necati Meral <necati_meral@yahoo.de>
Date: Fri, 22 Jan 2021 23:41:35 +0100
Subject: [PATCH 2/2] Fixed naming since it isn't strongly named (yet)

---
 src/WebHooks/WebHooks.sln                                     | 4 ++--
 .../AzureDevOpsCoreReceiver.csproj}                           | 0
 .../Controllers/AzureDevOpsController.cs                      | 0
 .../Program.cs                                                | 0
 .../Startup.cs                                                | 0
 .../appsettings.json                                          | 0
 .../AzureDevOpsWebHookAttribute.cs                            | 2 --
 7 files changed, 2 insertions(+), 4 deletions(-)
 rename src/WebHooks/samples/{AzureDevOpstronglyTypedCoreReceiver/AzureDevOpsStronglyTypedCoreReceiver.csproj => AzureDevOpsCoreReceiver/AzureDevOpsCoreReceiver.csproj} (100%)
 rename src/WebHooks/samples/{AzureDevOpstronglyTypedCoreReceiver => AzureDevOpsCoreReceiver}/Controllers/AzureDevOpsController.cs (100%)
 rename src/WebHooks/samples/{AzureDevOpstronglyTypedCoreReceiver => AzureDevOpsCoreReceiver}/Program.cs (100%)
 rename src/WebHooks/samples/{AzureDevOpstronglyTypedCoreReceiver => AzureDevOpsCoreReceiver}/Startup.cs (100%)
 rename src/WebHooks/samples/{AzureDevOpstronglyTypedCoreReceiver => AzureDevOpsCoreReceiver}/appsettings.json (100%)

diff --git a/src/WebHooks/WebHooks.sln b/src/WebHooks/WebHooks.sln
index 54467e146..25265ec19 100644
--- a/src/WebHooks/WebHooks.sln
+++ b/src/WebHooks/WebHooks.sln
@@ -101,7 +101,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebHoo
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps", "src\Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps\Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps.csproj", "{820D031D-237E-4892-A0BD-EF341421066A}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureDevOpsStronglyTypedCoreReceiver", "samples\AzureDevOpstronglyTypedCoreReceiver\AzureDevOpsStronglyTypedCoreReceiver.csproj", "{DAE01DE1-421B-420C-87DE-74ED9279A034}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureDevOpsCoreReceiver", "samples\AzureDevOpsCoreReceiver\AzureDevOpsCoreReceiver.csproj", "{DAE01DE1-421B-420C-87DE-74ED9279A034}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -306,7 +306,7 @@ Global
 		{DAE01DE1-421B-420C-87DE-74ED9279A034} = {E957C8D9-B4A0-488B-838F-BAB4DE080A76}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
-		EnterpriseLibraryConfigurationToolBinariesPathV6 = packages\EnterpriseLibrary.TransientFaultHandling.6.0.1304.0\lib\portable-net45+win+wp8;packages\EnterpriseLibrary.TransientFaultHandling.Data.6.0.1304.1\lib\NET45
 		SolutionGuid = {12CE6238-F847-4984-8622-1ED46072150A}
+		EnterpriseLibraryConfigurationToolBinariesPathV6 = packages\EnterpriseLibrary.TransientFaultHandling.6.0.1304.0\lib\portable-net45+win+wp8;packages\EnterpriseLibrary.TransientFaultHandling.Data.6.0.1304.1\lib\NET45
 	EndGlobalSection
 EndGlobal
diff --git a/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/AzureDevOpsStronglyTypedCoreReceiver.csproj b/src/WebHooks/samples/AzureDevOpsCoreReceiver/AzureDevOpsCoreReceiver.csproj
similarity index 100%
rename from src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/AzureDevOpsStronglyTypedCoreReceiver.csproj
rename to src/WebHooks/samples/AzureDevOpsCoreReceiver/AzureDevOpsCoreReceiver.csproj
diff --git a/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Controllers/AzureDevOpsController.cs b/src/WebHooks/samples/AzureDevOpsCoreReceiver/Controllers/AzureDevOpsController.cs
similarity index 100%
rename from src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Controllers/AzureDevOpsController.cs
rename to src/WebHooks/samples/AzureDevOpsCoreReceiver/Controllers/AzureDevOpsController.cs
diff --git a/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Program.cs b/src/WebHooks/samples/AzureDevOpsCoreReceiver/Program.cs
similarity index 100%
rename from src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Program.cs
rename to src/WebHooks/samples/AzureDevOpsCoreReceiver/Program.cs
diff --git a/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Startup.cs b/src/WebHooks/samples/AzureDevOpsCoreReceiver/Startup.cs
similarity index 100%
rename from src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/Startup.cs
rename to src/WebHooks/samples/AzureDevOpsCoreReceiver/Startup.cs
diff --git a/src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/appsettings.json b/src/WebHooks/samples/AzureDevOpsCoreReceiver/appsettings.json
similarity index 100%
rename from src/WebHooks/samples/AzureDevOpstronglyTypedCoreReceiver/appsettings.json
rename to src/WebHooks/samples/AzureDevOpsCoreReceiver/appsettings.json
diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/AzureDevOpsWebHookAttribute.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/AzureDevOpsWebHookAttribute.cs
index 13eef0629..15ba4a161 100644
--- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/AzureDevOpsWebHookAttribute.cs
+++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.AzureDevOps/AzureDevOpsWebHookAttribute.cs
@@ -47,8 +47,6 @@ namespace Microsoft.AspNetCore.WebHooks
     /// </remarks>
     public class AzureDevOpsWebHookAttribute : WebHookAttribute
     {
-        private string _eventName;
-
         /// <summary>
         /// Instantiates a new <see cref="AzureDevOpsWebHookAttribute"/> indicating the associated action is an Azure
         /// DevOps WebHook endpoint.