@ -0,0 +1,35 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.ComponentModel.DataAnnotations; | |||||
using Webhooks.API.Model; | |||||
namespace Webhooks.API.Controller | |||||
{ | |||||
public class WebhookSubscriptionRequest : IValidatableObject | |||||
{ | |||||
public string Url { get; set; } | |||||
public string Token { get; set; } | |||||
public string Event { get; set; } | |||||
public string GrantUrl { get; set; } | |||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) | |||||
{ | |||||
if (!Uri.IsWellFormedUriString(GrantUrl, UriKind.Absolute)) | |||||
{ | |||||
yield return new ValidationResult("GrantUrl is not valid", new[] { nameof(GrantUrl) }); | |||||
} | |||||
if (!Uri.IsWellFormedUriString(Url, UriKind.Absolute)) | |||||
{ | |||||
yield return new ValidationResult("Url is not valid", new[] { nameof(Url) }); | |||||
} | |||||
var isOk = Enum.TryParse<WebhookType>(Event, ignoreCase: true, result: out WebhookType whtype); | |||||
if (!isOk) | |||||
{ | |||||
yield return new ValidationResult($"{Event} is invalid event name", new[] { nameof(Event) }); | |||||
} | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,115 @@ | |||||
using Microsoft.AspNetCore.Authorization; | |||||
using Microsoft.AspNetCore.Mvc; | |||||
using Microsoft.EntityFrameworkCore; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Net; | |||||
using System.Threading.Tasks; | |||||
using Webhooks.API.Infrastructure; | |||||
using Webhooks.API.Model; | |||||
using Webhooks.API.Services; | |||||
namespace Webhooks.API.Controller | |||||
{ | |||||
[Route("api/v1/[controller]")] | |||||
[ApiController] | |||||
public class WebhooksController : ControllerBase | |||||
{ | |||||
private readonly WebhooksContext _dbContext; | |||||
private readonly IIdentityService _identityService; | |||||
private readonly IGrantUrlTesterService _grantUrlTester; | |||||
public WebhooksController(WebhooksContext dbContext, IIdentityService identityService, IGrantUrlTesterService grantUrlTester) | |||||
{ | |||||
_dbContext = dbContext; | |||||
_identityService = identityService; | |||||
_grantUrlTester = grantUrlTester; | |||||
} | |||||
[Authorize] | |||||
[HttpGet] | |||||
[ProducesResponseType(typeof(IEnumerable<WebhookSubscription>), (int)HttpStatusCode.OK)] | |||||
public async Task<IActionResult> ListByUser() | |||||
{ | |||||
var userId = _identityService.GetUserIdentity(); | |||||
var data = await _dbContext.Subscriptions.Where(s => s.UserId == userId).ToListAsync(); | |||||
return Ok(data); | |||||
} | |||||
[Authorize] | |||||
[HttpGet("{id:int}", Name = "Get")] | |||||
[ProducesResponseType(typeof(WebhookSubscription), (int)HttpStatusCode.OK)] | |||||
[ProducesResponseType((int)HttpStatusCode.NotFound)] | |||||
public async Task<IActionResult> GetByUserAndId(int id) | |||||
{ | |||||
var userId = _identityService.GetUserIdentity(); | |||||
var subscription = await _dbContext.Subscriptions.SingleOrDefaultAsync(s => s.Id == id && s.UserId == userId); | |||||
if (subscription != null) | |||||
{ | |||||
return Ok(subscription); | |||||
} | |||||
return NotFound($"Subscriptions {id} not found"); | |||||
} | |||||
[Authorize] | |||||
[HttpPost] | |||||
[ProducesResponseType((int)HttpStatusCode.Created)] | |||||
[ProducesResponseType((int)HttpStatusCode.BadRequest)] | |||||
[ProducesResponseType(418)] | |||||
public async Task<IActionResult> SubscribeWebhook(WebhookSubscriptionRequest request) | |||||
{ | |||||
if (!ModelState.IsValid) | |||||
{ | |||||
return ValidationProblem(ModelState); | |||||
} | |||||
var userId = _identityService.GetUserIdentity(); | |||||
var grantOk = await _grantUrlTester.TestGrantUrl(request.GrantUrl, request.Token ?? string.Empty); | |||||
if (grantOk) | |||||
{ | |||||
var subscription = new WebhookSubscription() | |||||
{ | |||||
Date = DateTime.UtcNow, | |||||
DestUrl = request.Url, | |||||
Token = request.Token, | |||||
Type = Enum.Parse<WebhookType>(request.Event, ignoreCase: true), | |||||
UserId = _identityService.GetUserIdentity() | |||||
}; | |||||
_dbContext.Add(subscription); | |||||
await _dbContext.SaveChangesAsync(); | |||||
return CreatedAtAction("Get", new { id = subscription.Id }); | |||||
} | |||||
else | |||||
{ | |||||
return StatusCode(418, "Grant url can't be validated"); | |||||
} | |||||
} | |||||
[Authorize] | |||||
[HttpDelete("{id:int}")] | |||||
[ProducesResponseType((int)HttpStatusCode.Accepted)] | |||||
[ProducesResponseType((int)HttpStatusCode.NotFound)] | |||||
public async Task<IActionResult> UnsubscribeWebhook(int id) | |||||
{ | |||||
var userId = _identityService.GetUserIdentity(); | |||||
var subscription = await _dbContext.Subscriptions.SingleOrDefaultAsync(s => s.Id == id && s.UserId == userId); | |||||
if (subscription != null) | |||||
{ | |||||
_dbContext.Remove(subscription); | |||||
await _dbContext.SaveChangesAsync(); | |||||
return Accepted(); | |||||
} | |||||
return NotFound($"Subscriptions {id} not found"); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,19 @@ | |||||
FROM microsoft/dotnet:2.2-aspnetcore-runtime AS base | |||||
WORKDIR /app | |||||
EXPOSE 80 | |||||
FROM microsoft/dotnet:2.2-sdk AS build | |||||
WORKDIR /src | |||||
COPY ["src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj", "src/Services/Webhooks/Webhooks.API/"] | |||||
RUN dotnet restore "src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj" | |||||
COPY . . | |||||
WORKDIR "/src/src/Services/Webhooks/Webhooks.API" | |||||
RUN dotnet build "Webhooks.API.csproj" -c Release -o /app | |||||
FROM build AS publish | |||||
RUN dotnet publish "Webhooks.API.csproj" -c Release -o /app | |||||
FROM base AS final | |||||
WORKDIR /app | |||||
COPY --from=publish /app . | |||||
ENTRYPOINT ["dotnet", "Webhooks.API.dll"] |
@ -0,0 +1,11 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
namespace Webhooks.API.Exceptions | |||||
{ | |||||
public class WebhooksDomainException : Exception | |||||
{ | |||||
} | |||||
} |
@ -0,0 +1,13 @@ | |||||
using Microsoft.AspNetCore.Http; | |||||
using Microsoft.AspNetCore.Mvc; | |||||
namespace Webhooks.API.Infrastructure.ActionResult | |||||
{ | |||||
class InternalServerErrorObjectResult : ObjectResult | |||||
{ | |||||
public InternalServerErrorObjectResult(object error) : base(error) | |||||
{ | |||||
StatusCode = StatusCodes.Status500InternalServerError; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,72 @@ | |||||
using Microsoft.AspNetCore.Hosting; | |||||
using Microsoft.AspNetCore.Http; | |||||
using Microsoft.AspNetCore.Mvc; | |||||
using Microsoft.AspNetCore.Mvc.Filters; | |||||
using Microsoft.Extensions.Logging; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Net; | |||||
using System.Threading.Tasks; | |||||
using Webhooks.API.Exceptions; | |||||
using Webhooks.API.Infrastructure.ActionResult; | |||||
namespace Webhooks.API.Infrastructure | |||||
{ | |||||
public class HttpGlobalExceptionFilter : IExceptionFilter | |||||
{ | |||||
private readonly IHostingEnvironment env; | |||||
private readonly ILogger<HttpGlobalExceptionFilter> logger; | |||||
public HttpGlobalExceptionFilter(IHostingEnvironment env, ILogger<HttpGlobalExceptionFilter> logger) | |||||
{ | |||||
this.env = env; | |||||
this.logger = logger; | |||||
} | |||||
public void OnException(ExceptionContext context) | |||||
{ | |||||
logger.LogError(new EventId(context.Exception.HResult), | |||||
context.Exception, | |||||
context.Exception.Message); | |||||
if (context.Exception.GetType() == typeof(WebhooksDomainException)) | |||||
{ | |||||
var problemDetails = new ValidationProblemDetails() | |||||
{ | |||||
Instance = context.HttpContext.Request.Path, | |||||
Status = StatusCodes.Status400BadRequest, | |||||
Detail = "Please refer to the errors property for additional details." | |||||
}; | |||||
problemDetails.Errors.Add("DomainValidations", new string[] { context.Exception.Message.ToString() }); | |||||
context.Result = new BadRequestObjectResult(problemDetails); | |||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest; | |||||
} | |||||
else | |||||
{ | |||||
var json = new JsonErrorResponse | |||||
{ | |||||
Messages = new[] { "An error ocurred." } | |||||
}; | |||||
if (env.IsDevelopment()) | |||||
{ | |||||
json.DeveloperMeesage = context.Exception; | |||||
} | |||||
context.Result = new InternalServerErrorObjectResult(json); | |||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError; | |||||
} | |||||
context.ExceptionHandled = true; | |||||
} | |||||
private class JsonErrorResponse | |||||
{ | |||||
public string[] Messages { get; set; } | |||||
public object DeveloperMeesage { get; set; } | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,18 @@ | |||||
using Microsoft.EntityFrameworkCore; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
using Webhooks.API.Model; | |||||
namespace Webhooks.API.Infrastructure | |||||
{ | |||||
public class WebhooksContext : DbContext | |||||
{ | |||||
public WebhooksContext(DbContextOptions<WebhooksContext> options) : base(options) | |||||
{ | |||||
} | |||||
public DbSet<WebhookSubscription> Subscriptions { get; set; } | |||||
} | |||||
} |
@ -0,0 +1,18 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
namespace Webhooks.API.Model | |||||
{ | |||||
public class WebhookSubscription | |||||
{ | |||||
public int Id { get; set; } | |||||
public WebhookType Type { get; set; } | |||||
public DateTime Date { get; set; } | |||||
public string DestUrl { get; set; } | |||||
public string Token { get; set; } | |||||
public string UserId { get; set; } | |||||
} | |||||
} |
@ -0,0 +1,12 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
namespace Webhooks.API.Model | |||||
{ | |||||
public enum WebhookType | |||||
{ | |||||
CatalogItemPriceChange = 1 | |||||
} | |||||
} |
@ -0,0 +1,27 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
using Microsoft.AspNetCore; | |||||
using Microsoft.AspNetCore.Hosting; | |||||
using Microsoft.Extensions.Configuration; | |||||
using Microsoft.Extensions.Logging; | |||||
using Webhooks.API.Infrastructure; | |||||
namespace Webhooks.API | |||||
{ | |||||
public class Program | |||||
{ | |||||
public static void Main(string[] args) | |||||
{ | |||||
CreateWebHostBuilder(args).Build() | |||||
.MigrateDbContext<WebhooksContext>((_,__) => { }) | |||||
.Run(); | |||||
} | |||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => | |||||
WebHost.CreateDefaultBuilder(args) | |||||
.UseStartup<Startup>(); | |||||
} | |||||
} |
@ -0,0 +1,32 @@ | |||||
{ | |||||
"iisSettings": { | |||||
"windowsAuthentication": false, | |||||
"anonymousAuthentication": true, | |||||
"iisExpress": { | |||||
"applicationUrl": "http://localhost:62486", | |||||
"sslPort": 0 | |||||
} | |||||
}, | |||||
"profiles": { | |||||
"IIS Express": { | |||||
"commandName": "IISExpress", | |||||
"launchBrowser": true, | |||||
"environmentVariables": { | |||||
"ASPNETCORE_ENVIRONMENT": "Development" | |||||
} | |||||
}, | |||||
"Webhooks.API": { | |||||
"commandName": "Project", | |||||
"launchBrowser": true, | |||||
"environmentVariables": { | |||||
"ASPNETCORE_ENVIRONMENT": "Development" | |||||
}, | |||||
"applicationUrl": "http://localhost:5000" | |||||
}, | |||||
"Docker": { | |||||
"commandName": "Docker", | |||||
"launchBrowser": true, | |||||
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}" | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,27 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Net.Http; | |||||
using System.Threading.Tasks; | |||||
namespace Webhooks.API.Services | |||||
{ | |||||
class GrantUrlTesterService : IGrantUrlTesterService | |||||
{ | |||||
private readonly IHttpClientFactory _clientFactory; | |||||
public GrantUrlTesterService(IHttpClientFactory factory) | |||||
{ | |||||
_clientFactory = factory; | |||||
} | |||||
public async Task<bool> TestGrantUrl(string url, string token) | |||||
{ | |||||
var client = _clientFactory.CreateClient("GrantClient"); | |||||
var msg = new HttpRequestMessage(HttpMethod.Options, url); | |||||
msg.Headers.Add("X-eshop-whtoken", token); | |||||
var response = await client.SendAsync(msg); | |||||
return response.IsSuccessStatusCode; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,12 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
namespace Webhooks.API.Services | |||||
{ | |||||
public interface IGrantUrlTesterService | |||||
{ | |||||
Task<bool> TestGrantUrl(string url, string token); | |||||
} | |||||
} |
@ -0,0 +1,7 @@ | |||||
namespace Webhooks.API.Services | |||||
{ | |||||
public interface IIdentityService | |||||
{ | |||||
string GetUserIdentity(); | |||||
} | |||||
} |
@ -0,0 +1,21 @@ | |||||
| |||||
using Microsoft.AspNetCore.Http; | |||||
using System; | |||||
namespace Webhooks.API.Services | |||||
{ | |||||
public class IdentityService : IIdentityService | |||||
{ | |||||
private IHttpContextAccessor _context; | |||||
public IdentityService(IHttpContextAccessor context) | |||||
{ | |||||
_context = context ?? throw new ArgumentNullException(nameof(context)); | |||||
} | |||||
public string GetUserIdentity() | |||||
{ | |||||
return _context.HttpContext.User.FindFirst("sub").Value; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,333 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Data.Common; | |||||
using System.Linq; | |||||
using System.Reflection; | |||||
using System.Threading; | |||||
using System.Threading.Tasks; | |||||
using Autofac; | |||||
using HealthChecks.UI.Client; | |||||
using Microsoft.ApplicationInsights.Extensibility; | |||||
using Microsoft.ApplicationInsights.ServiceFabric; | |||||
using Microsoft.AspNetCore.Builder; | |||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks; | |||||
using Microsoft.AspNetCore.Hosting; | |||||
using Microsoft.AspNetCore.Http; | |||||
using Microsoft.AspNetCore.Mvc; | |||||
using Microsoft.Azure.ServiceBus; | |||||
using Microsoft.EntityFrameworkCore; | |||||
using Microsoft.EntityFrameworkCore.Diagnostics; | |||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; | |||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | |||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; | |||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; | |||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services; | |||||
using Microsoft.Extensions.Configuration; | |||||
using Microsoft.Extensions.DependencyInjection; | |||||
using Microsoft.Extensions.Diagnostics.HealthChecks; | |||||
using Microsoft.Extensions.Logging; | |||||
using RabbitMQ.Client; | |||||
using Swashbuckle.AspNetCore.Swagger; | |||||
using Webhooks.API.Infrastructure; | |||||
using Webhooks.API.Services; | |||||
namespace Webhooks.API | |||||
{ | |||||
public class Startup | |||||
{ | |||||
public IConfiguration Configuration { get; } | |||||
public Startup(IConfiguration configuration) | |||||
{ | |||||
Configuration = configuration; | |||||
} | |||||
public void ConfigureServices(IServiceCollection services) | |||||
{ | |||||
services | |||||
.AddAppInsight(Configuration) | |||||
.AddCustomMVC(Configuration) | |||||
.AddCustomDbContext(Configuration) | |||||
.AddSwagger(Configuration) | |||||
.AddCustomHealthCheck(Configuration) | |||||
.AddHttpClientServices(Configuration) | |||||
.AddIntegrationServices(Configuration) | |||||
.AddEventBus(Configuration) | |||||
.AddTransient<IIdentityService, IdentityService>() | |||||
.AddTransient<IGrantUrlTesterService, GrantUrlTesterService>(); | |||||
} | |||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) | |||||
{ | |||||
loggerFactory.AddAzureWebAppDiagnostics(); | |||||
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace); | |||||
var pathBase = Configuration["PATH_BASE"]; | |||||
if (!string.IsNullOrEmpty(pathBase)) | |||||
{ | |||||
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'"); | |||||
app.UsePathBase(pathBase); | |||||
} | |||||
app.UseHealthChecks("/hc", new HealthCheckOptions() | |||||
{ | |||||
Predicate = _ => true, | |||||
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse | |||||
}); | |||||
app.UseHealthChecks("/liveness", new HealthCheckOptions | |||||
{ | |||||
Predicate = r => r.Name.Contains("self") | |||||
}); | |||||
app.UseCors("CorsPolicy"); | |||||
app.UseMvcWithDefaultRoute(); | |||||
app.UseSwagger() | |||||
.UseSwaggerUI(c => | |||||
{ | |||||
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Webhooks.API V1"); | |||||
c.OAuthClientId("webhooksswaggerui"); | |||||
c.OAuthAppName("WebHooks Service Swagger UI"); | |||||
}); | |||||
ConfigureEventBus(app); | |||||
} | |||||
protected virtual void ConfigureEventBus(IApplicationBuilder app) | |||||
{ | |||||
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>(); | |||||
// eventBus.Subscribe<OrderStatusChangedToAwaitingValidationIntegrationEvent, OrderStatusChangedToAwaitingValidationIntegrationEventHandler>(); | |||||
} | |||||
} | |||||
static class CustomExtensionMethods | |||||
{ | |||||
public static IServiceCollection AddAppInsight(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
services.AddApplicationInsightsTelemetry(configuration); | |||||
var orchestratorType = configuration.GetValue<string>("OrchestratorType"); | |||||
if (orchestratorType?.ToUpper() == "K8S") | |||||
{ | |||||
// Enable K8s telemetry initializer | |||||
services.EnableKubernetes(); | |||||
} | |||||
if (orchestratorType?.ToUpper() == "SF") | |||||
{ | |||||
// Enable SF telemetry initializer | |||||
services.AddSingleton<ITelemetryInitializer>((serviceProvider) => | |||||
new FabricTelemetryInitializer()); | |||||
} | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddCustomMVC(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
services.AddMvc(options => | |||||
{ | |||||
options.Filters.Add(typeof(HttpGlobalExceptionFilter)); | |||||
}) | |||||
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2) | |||||
.AddControllersAsServices(); | |||||
services.AddCors(options => | |||||
{ | |||||
options.AddPolicy("CorsPolicy", | |||||
builder => builder | |||||
.SetIsOriginAllowed((host) => true) | |||||
.AllowAnyMethod() | |||||
.AllowAnyHeader() | |||||
.AllowCredentials()); | |||||
}); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddCustomDbContext(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
services.AddDbContext<WebhooksContext>(options => | |||||
{ | |||||
options.UseSqlServer(configuration["ConnectionString"], | |||||
sqlServerOptionsAction: sqlOptions => | |||||
{ | |||||
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); | |||||
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency | |||||
sqlOptions.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); | |||||
}); | |||||
// Changing default behavior when client evaluation occurs to throw. | |||||
// Default in EF Core would be to log a warning when client evaluation is performed. | |||||
options.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning)); | |||||
//Check Client vs. Server evaluation: https://docs.microsoft.com/en-us/ef/core/querying/client-eval | |||||
}); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddSwagger(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
services.AddSwaggerGen(options => | |||||
{ | |||||
options.DescribeAllEnumsAsStrings(); | |||||
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info | |||||
{ | |||||
Title = "eShopOnContainers - Webhooks HTTP API", | |||||
Version = "v1", | |||||
Description = "The Webhooks Microservice HTTP API. This is a simple webhooks CRUD registration entrypoint", | |||||
TermsOfService = "Terms Of Service" | |||||
}); | |||||
options.AddSecurityDefinition("oauth2", new OAuth2Scheme | |||||
{ | |||||
Type = "oauth2", | |||||
Flow = "implicit", | |||||
AuthorizationUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize", | |||||
TokenUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token", | |||||
Scopes = new Dictionary<string, string>() | |||||
{ | |||||
{ "webhooks", "Webhooks.API" } | |||||
} | |||||
}); | |||||
}); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
var subscriptionClientName = configuration["SubscriptionClientName"]; | |||||
if (configuration.GetValue<bool>("AzureServiceBusEnabled")) | |||||
{ | |||||
services.AddSingleton<IEventBus, EventBusServiceBus>(sp => | |||||
{ | |||||
var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>(); | |||||
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>(); | |||||
var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); | |||||
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); | |||||
return new EventBusServiceBus(serviceBusPersisterConnection, logger, | |||||
eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); | |||||
}); | |||||
} | |||||
else | |||||
{ | |||||
services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp => | |||||
{ | |||||
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>(); | |||||
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>(); | |||||
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>(); | |||||
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); | |||||
var retryCount = 5; | |||||
if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"])) | |||||
{ | |||||
retryCount = int.Parse(configuration["EventBusRetryCount"]); | |||||
} | |||||
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount); | |||||
}); | |||||
} | |||||
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>(); | |||||
//services.AddTransient<OrderStatusChangedToAwaitingValidationIntegrationEventHandler>(); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
var accountName = configuration.GetValue<string>("AzureStorageAccountName"); | |||||
var accountKey = configuration.GetValue<string>("AzureStorageAccountKey"); | |||||
var hcBuilder = services.AddHealthChecks(); | |||||
hcBuilder | |||||
.AddCheck("self", () => HealthCheckResult.Healthy()) | |||||
.AddSqlServer( | |||||
configuration["ConnectionString"], | |||||
name: "WebhooksApiDb-check", | |||||
tags: new string[] { "webhooksdb" }); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddHttpClientServices(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); | |||||
//register delegating handlers | |||||
//services.AddTransient<HttpClientAuthorizationDelegatingHandler>(); | |||||
//InfinteTimeSpan -> See: https://github.com/aspnet/HttpClientFactory/issues/194 | |||||
services.AddHttpClient("extendedhandlerlifetime").SetHandlerLifetime(Timeout.InfiniteTimeSpan); | |||||
//add http client services | |||||
services.AddHttpClient("GrantClient") | |||||
.SetHandlerLifetime(TimeSpan.FromMinutes(5)); | |||||
//.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>(); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddIntegrationServices(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>( | |||||
sp => (DbConnection c) => new IntegrationEventLogService(c)); | |||||
// services.AddTransient<ICatalogIntegrationEventService, CatalogIntegrationEventService>(); | |||||
if (configuration.GetValue<bool>("AzureServiceBusEnabled")) | |||||
{ | |||||
services.AddSingleton<IServiceBusPersisterConnection>(sp => | |||||
{ | |||||
var logger = sp.GetRequiredService<ILogger<DefaultServiceBusPersisterConnection>>(); | |||||
var serviceBusConnection = new ServiceBusConnectionStringBuilder(configuration["EventBusConnection"]); | |||||
return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger); | |||||
}); | |||||
} | |||||
else | |||||
{ | |||||
services.AddSingleton<IRabbitMQPersistentConnection>(sp => | |||||
{ | |||||
var logger = sp.GetRequiredService<ILogger<DefaultRabbitMQPersistentConnection>>(); | |||||
var factory = new ConnectionFactory() | |||||
{ | |||||
HostName = configuration["EventBusConnection"] | |||||
}; | |||||
if (!string.IsNullOrEmpty(configuration["EventBusUserName"])) | |||||
{ | |||||
factory.UserName = configuration["EventBusUserName"]; | |||||
} | |||||
if (!string.IsNullOrEmpty(configuration["EventBusPassword"])) | |||||
{ | |||||
factory.Password = configuration["EventBusPassword"]; | |||||
} | |||||
var retryCount = 5; | |||||
if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"])) | |||||
{ | |||||
retryCount = int.Parse(configuration["EventBusRetryCount"]); | |||||
} | |||||
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount); | |||||
}); | |||||
} | |||||
return services; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,31 @@ | |||||
<Project Sdk="Microsoft.NET.Sdk.Web"> | |||||
<PropertyGroup> | |||||
<TargetFramework>netcoreapp2.2</TargetFramework> | |||||
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel> | |||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<PackageReference Include="Microsoft.AspNetCore.App" /> | |||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" /> | |||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.0.2105168" /> | |||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" /> | |||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" /> | |||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" /> | |||||
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1-beta1" /> | |||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" /> | |||||
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" /> | |||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.0" /> | |||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" /> | |||||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="2.2.0" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" /> | |||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" /> | |||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" /> | |||||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.csproj" /> | |||||
<ProjectReference Include="..\..\..\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj" /> | |||||
</ItemGroup> | |||||
</Project> |
@ -0,0 +1,9 @@ | |||||
{ | |||||
"Logging": { | |||||
"LogLevel": { | |||||
"Default": "Debug", | |||||
"System": "Information", | |||||
"Microsoft": "Information" | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,8 @@ | |||||
{ | |||||
"Logging": { | |||||
"LogLevel": { | |||||
"Default": "Warning" | |||||
} | |||||
}, | |||||
"AllowedHosts": "*" | |||||
} |
@ -0,0 +1,20 @@ | |||||
FROM microsoft/dotnet:2.2-aspnetcore-runtime AS base | |||||
WORKDIR /app | |||||
EXPOSE 80 | |||||
EXPOSE 443 | |||||
FROM microsoft/dotnet:2.2-sdk AS build | |||||
WORKDIR /src | |||||
COPY ["src/Web/WebhookClient/WebhookClient.csproj", "src/Web/WebhookClient/"] | |||||
RUN dotnet restore "src/Web/WebhookClient/WebhookClient.csproj" | |||||
COPY . . | |||||
WORKDIR "/src/src/Web/WebhookClient" | |||||
RUN dotnet build "WebhookClient.csproj" -c Release -o /app | |||||
FROM build AS publish | |||||
RUN dotnet publish "WebhookClient.csproj" -c Release -o /app | |||||
FROM base AS final | |||||
WORKDIR /app | |||||
COPY --from=publish /app . | |||||
ENTRYPOINT ["dotnet", "WebhookClient.dll"] |
@ -0,0 +1,12 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
namespace WebhookClient | |||||
{ | |||||
static class HeaderNames | |||||
{ | |||||
public const string WebHookCheckHeader = "X-eshop-whtoken"; | |||||
} | |||||
} |
@ -0,0 +1,26 @@ | |||||
@page | |||||
@model ErrorModel | |||||
@{ | |||||
ViewData["Title"] = "Error"; | |||||
} | |||||
<h1 class="text-danger">Error.</h1> | |||||
<h2 class="text-danger">An error occurred while processing your request.</h2> | |||||
@if (Model.ShowRequestId) | |||||
{ | |||||
<p> | |||||
<strong>Request ID:</strong> <code>@Model.RequestId</code> | |||||
</p> | |||||
} | |||||
<h3>Development Mode</h3> | |||||
<p> | |||||
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred. | |||||
</p> | |||||
<p> | |||||
<strong>The Development environment shouldn't be enabled for deployed applications.</strong> | |||||
It can result in displaying sensitive information from exceptions to end users. | |||||
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong> | |||||
and restarting the app. | |||||
</p> |
@ -0,0 +1,23 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Diagnostics; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
using Microsoft.AspNetCore.Mvc; | |||||
using Microsoft.AspNetCore.Mvc.RazorPages; | |||||
namespace WebhookClient.Pages | |||||
{ | |||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] | |||||
public class ErrorModel : PageModel | |||||
{ | |||||
public string RequestId { get; set; } | |||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); | |||||
public void OnGet() | |||||
{ | |||||
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,10 @@ | |||||
@page | |||||
@model IndexModel | |||||
@{ | |||||
ViewData["Title"] = "Home page"; | |||||
} | |||||
<div class="text-center"> | |||||
<h1 class="display-4">Welcome</h1> | |||||
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p> | |||||
</div> |
@ -0,0 +1,17 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
using Microsoft.AspNetCore.Mvc; | |||||
using Microsoft.AspNetCore.Mvc.RazorPages; | |||||
namespace WebhookClient.Pages | |||||
{ | |||||
public class IndexModel : PageModel | |||||
{ | |||||
public void OnGet() | |||||
{ | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,8 @@ | |||||
@page | |||||
@model PrivacyModel | |||||
@{ | |||||
ViewData["Title"] = "Privacy Policy"; | |||||
} | |||||
<h1>@ViewData["Title"]</h1> | |||||
<p>Use this page to detail your site's privacy policy.</p> |
@ -0,0 +1,16 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
using Microsoft.AspNetCore.Mvc; | |||||
using Microsoft.AspNetCore.Mvc.RazorPages; | |||||
namespace WebhookClient.Pages | |||||
{ | |||||
public class PrivacyModel : PageModel | |||||
{ | |||||
public void OnGet() | |||||
{ | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,25 @@ | |||||
@using Microsoft.AspNetCore.Http.Features | |||||
@{ | |||||
var consentFeature = Context.Features.Get<ITrackingConsentFeature>(); | |||||
var showBanner = !consentFeature?.CanTrack ?? false; | |||||
var cookieString = consentFeature?.CreateConsentCookie(); | |||||
} | |||||
@if (showBanner) | |||||
{ | |||||
<div id="cookieConsent" class="alert alert-info alert-dismissible fade show" role="alert"> | |||||
Use this space to summarize your privacy and cookie use policy. <a asp-page="/Privacy">Learn More</a>. | |||||
<button type="button" class="accept-policy close" data-dismiss="alert" aria-label="Close" data-cookie-string="@cookieString"> | |||||
<span aria-hidden="true">Accept</span> | |||||
</button> | |||||
</div> | |||||
<script> | |||||
(function () { | |||||
var button = document.querySelector("#cookieConsent button[data-cookie-string]"); | |||||
button.addEventListener("click", function (event) { | |||||
document.cookie = button.dataset.cookieString; | |||||
}, false); | |||||
})(); | |||||
</script> | |||||
} |
@ -0,0 +1,77 @@ | |||||
<!DOCTYPE html> | |||||
<html> | |||||
<head> | |||||
<meta charset="utf-8" /> | |||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |||||
<title>@ViewData["Title"] - WebhookClient</title> | |||||
<environment include="Development"> | |||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" /> | |||||
</environment> | |||||
<environment exclude="Development"> | |||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" | |||||
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css" | |||||
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" | |||||
crossorigin="anonymous" | |||||
integrity="sha256-eSi1q2PG6J7g7ib17yAaWMcrr5GrtohYChqibrV7PBE="/> | |||||
</environment> | |||||
<link rel="stylesheet" href="~/css/site.css" /> | |||||
</head> | |||||
<body> | |||||
<header> | |||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3"> | |||||
<div class="container"> | |||||
<a class="navbar-brand" asp-area="" asp-page="/Index">WebhookClient</a> | |||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent" | |||||
aria-expanded="false" aria-label="Toggle navigation"> | |||||
<span class="navbar-toggler-icon"></span> | |||||
</button> | |||||
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse"> | |||||
<ul class="navbar-nav flex-grow-1"> | |||||
<li class="nav-item"> | |||||
<a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a> | |||||
</li> | |||||
<li class="nav-item"> | |||||
<a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a> | |||||
</li> | |||||
</ul> | |||||
</div> | |||||
</div> | |||||
</nav> | |||||
</header> | |||||
<div class="container"> | |||||
<partial name="_CookieConsentPartial" /> | |||||
<main role="main" class="pb-3"> | |||||
@RenderBody() | |||||
</main> | |||||
</div> | |||||
<footer class="border-top footer text-muted"> | |||||
<div class="container"> | |||||
© 2019 - WebhookClient - <a asp-area="" asp-page="/Privacy">Privacy</a> | |||||
</div> | |||||
</footer> | |||||
<environment include="Development"> | |||||
<script src="~/lib/jquery/dist/jquery.js"></script> | |||||
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script> | |||||
</environment> | |||||
<environment exclude="Development"> | |||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" | |||||
asp-fallback-src="~/lib/jquery/dist/jquery.min.js" | |||||
asp-fallback-test="window.jQuery" | |||||
crossorigin="anonymous" | |||||
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="> | |||||
</script> | |||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.bundle.min.js" | |||||
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js" | |||||
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal" | |||||
crossorigin="anonymous" | |||||
integrity="sha256-E/V4cWE4qvAeO5MOhjtGtqDzPndRO1LBk8lJ/PR7CA4="> | |||||
</script> | |||||
</environment> | |||||
<script src="~/js/site.js" asp-append-version="true"></script> | |||||
@RenderSection("Scripts", required: false) | |||||
</body> | |||||
</html> |
@ -0,0 +1,18 @@ | |||||
<environment include="Development"> | |||||
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script> | |||||
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script> | |||||
</environment> | |||||
<environment exclude="Development"> | |||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js" | |||||
asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js" | |||||
asp-fallback-test="window.jQuery && window.jQuery.validator" | |||||
crossorigin="anonymous" | |||||
integrity="sha256-F6h55Qw6sweK+t7SiOJX+2bpSAa3b/fnlrVCJvmEj1A="> | |||||
</script> | |||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js" | |||||
asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js" | |||||
asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive" | |||||
crossorigin="anonymous" | |||||
integrity="sha256-9GycpJnliUjJDVDqP0UEu/bsm9U+3dnQUH8+3W10vkY="> | |||||
</script> | |||||
</environment> |
@ -0,0 +1,3 @@ | |||||
@using WebhookClient | |||||
@namespace WebhookClient.Pages | |||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
@ -0,0 +1,3 @@ | |||||
@{ | |||||
Layout = "_Layout"; | |||||
} |
@ -0,0 +1,24 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
using Microsoft.AspNetCore; | |||||
using Microsoft.AspNetCore.Hosting; | |||||
using Microsoft.Extensions.Configuration; | |||||
using Microsoft.Extensions.Logging; | |||||
namespace WebhookClient | |||||
{ | |||||
public class Program | |||||
{ | |||||
public static void Main(string[] args) | |||||
{ | |||||
CreateWebHostBuilder(args).Build().Run(); | |||||
} | |||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => | |||||
WebHost.CreateDefaultBuilder(args) | |||||
.UseStartup<Startup>(); | |||||
} | |||||
} |
@ -0,0 +1,32 @@ | |||||
{ | |||||
"iisSettings": { | |||||
"windowsAuthentication": false, | |||||
"anonymousAuthentication": true, | |||||
"iisExpress": { | |||||
"applicationUrl": "http://localhost:51921", | |||||
"sslPort": 44398 | |||||
} | |||||
}, | |||||
"profiles": { | |||||
"IIS Express": { | |||||
"commandName": "IISExpress", | |||||
"launchBrowser": true, | |||||
"environmentVariables": { | |||||
"ASPNETCORE_ENVIRONMENT": "Development" | |||||
} | |||||
}, | |||||
"WebhookClient": { | |||||
"commandName": "Project", | |||||
"launchBrowser": true, | |||||
"environmentVariables": { | |||||
"ASPNETCORE_ENVIRONMENT": "Development" | |||||
}, | |||||
"applicationUrl": "https://localhost:5001;http://localhost:5000" | |||||
}, | |||||
"Docker": { | |||||
"commandName": "Docker", | |||||
"launchBrowser": true, | |||||
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}" | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,81 @@ | |||||
using Microsoft.AspNetCore.Builder; | |||||
using Microsoft.AspNetCore.Hosting; | |||||
using Microsoft.AspNetCore.Http; | |||||
using Microsoft.AspNetCore.Mvc; | |||||
using Microsoft.Extensions.Configuration; | |||||
using Microsoft.Extensions.DependencyInjection; | |||||
using System; | |||||
using System.Linq; | |||||
using System.Net; | |||||
namespace WebhookClient | |||||
{ | |||||
public class Startup | |||||
{ | |||||
public Startup(IConfiguration configuration) | |||||
{ | |||||
Configuration = configuration; | |||||
} | |||||
public IConfiguration Configuration { get; } | |||||
// This method gets called by the runtime. Use this method to add services to the container. | |||||
public void ConfigureServices(IServiceCollection services) | |||||
{ | |||||
services.Configure<CookiePolicyOptions>(options => | |||||
{ | |||||
// This lambda determines whether user consent for non-essential cookies is needed for a given request. | |||||
options.CheckConsentNeeded = context => true; | |||||
options.MinimumSameSitePolicy = SameSiteMode.None; | |||||
}); | |||||
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); | |||||
} | |||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. | |||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env) | |||||
{ | |||||
if (env.IsDevelopment()) | |||||
{ | |||||
app.UseDeveloperExceptionPage(); | |||||
} | |||||
else | |||||
{ | |||||
app.UseExceptionHandler("/Error"); | |||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. | |||||
app.UseHsts(); | |||||
} | |||||
app.UseHttpsRedirection(); | |||||
app.Map("/check", capp => | |||||
{ | |||||
capp.Run(async (context) => | |||||
{ | |||||
if ("OPTIONS".Equals(context.Request.Method, StringComparison.InvariantCultureIgnoreCase)) | |||||
{ | |||||
var header = context.Request.Headers[HeaderNames.WebHookCheckHeader]; | |||||
var value = header.FirstOrDefault(); | |||||
if (value == Configuration["Token"]) | |||||
{ | |||||
context.Response.StatusCode = (int)HttpStatusCode.OK; | |||||
} | |||||
else | |||||
{ | |||||
await context.Response.WriteAsync("Invalid token"); | |||||
context.Response.StatusCode = (int)HttpStatusCode.BadRequest; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
context.Response.StatusCode = (int)HttpStatusCode.BadRequest; | |||||
} | |||||
}); | |||||
}); | |||||
app.UseStaticFiles(); | |||||
app.UseCookiePolicy(); | |||||
app.UseMvc(); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,17 @@ | |||||
<Project Sdk="Microsoft.NET.Sdk.Web"> | |||||
<PropertyGroup> | |||||
<TargetFramework>netcoreapp2.2</TargetFramework> | |||||
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel> | |||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> | |||||
<UserSecretsId>36215d41-f31a-4aa6-9929-bd67d650e7b5</UserSecretsId> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<PackageReference Include="Microsoft.AspNetCore.App" /> | |||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" /> | |||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.0.2105168" /> | |||||
</ItemGroup> | |||||
</Project> |
@ -0,0 +1,10 @@ | |||||
{ | |||||
"Logging": { | |||||
"LogLevel": { | |||||
"Default": "Debug", | |||||
"System": "Information", | |||||
"Microsoft": "Information" | |||||
}, | |||||
"Token": "6168DB8D-DC58-4094-AF24-483278923590" | |||||
} | |||||
} |
@ -0,0 +1,8 @@ | |||||
{ | |||||
"Logging": { | |||||
"LogLevel": { | |||||
"Default": "Warning" | |||||
} | |||||
}, | |||||
"AllowedHosts": "*" | |||||
} |