program config
parent
5416c982a5
commit
182d17c73c
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\IdentityServer.Application\IdentityServer.Application.csproj" />
|
<ProjectReference Include="..\IdentityServer.Application\IdentityServer.Application.csproj" />
|
||||||
|
<ProjectReference Include="..\IdentityServer.Domain.Data\IdentityServer.Domain.Data.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Serilog;
|
||||||
|
using Serilog.Core;
|
||||||
|
using Serilog.Events;
|
||||||
|
using Serilog.Sinks.MSSqlServer;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace IdentityServer.Api
|
namespace IdentityServer.Api
|
||||||
{
|
{
|
||||||
|
@ -13,14 +16,69 @@ namespace IdentityServer.Api
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
CreateHostBuilder(args).Build().Run();
|
var isConsole = Debugger.IsAttached || args.Contains("--console");
|
||||||
|
if (!isConsole)
|
||||||
|
{
|
||||||
|
var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
|
||||||
|
var pathToContentRoot = Path.GetDirectoryName(pathToExe);
|
||||||
|
Directory.SetCurrentDirectory(pathToContentRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
var configuration = new ConfigurationBuilder()
|
||||||
Host.CreateDefaultBuilder(args)
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var connectionString = configuration.GetConnectionString("DatabaseConnection");
|
||||||
|
var loggingLevelParam = configuration.GetValue<string>("Logging:LogLevel:Default");
|
||||||
|
|
||||||
|
Enum.TryParse(loggingLevelParam, out LogEventLevel loggingLevel);
|
||||||
|
var loggingLevelSwitch = new LoggingLevelSwitch(loggingLevel);
|
||||||
|
|
||||||
|
var columnOptions = new ColumnOptions();
|
||||||
|
columnOptions.Store.Remove(StandardColumn.Properties);
|
||||||
|
columnOptions.Store.Remove(StandardColumn.MessageTemplate);
|
||||||
|
columnOptions.Store.Add(StandardColumn.LogEvent);
|
||||||
|
Log.Logger = new LoggerConfiguration()
|
||||||
|
.MinimumLevel.ControlledBy(loggingLevelSwitch)
|
||||||
|
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.MSSqlServer(connectionString, "__Logs", autoCreateSqlTable: true, columnOptions: columnOptions)
|
||||||
|
.CreateLogger();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var urls = configuration.GetValue<string>("urls");
|
||||||
|
Log.Information("Starting identity server API...");
|
||||||
|
Log.Information($"API listening on {urls}");
|
||||||
|
Console.WriteLine("Application started. Press Ctrl+C to shut down.");
|
||||||
|
CreateHostBuilder(args, configuration, !isConsole).Build().Run();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Fatal(ex, "Identity server API host terminated unexpectedly");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Log.CloseAndFlush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IHostBuilder CreateHostBuilder(string[] args, IConfiguration configuration, bool useWindowsService)
|
||||||
|
{
|
||||||
|
var builder = Host.CreateDefaultBuilder(args)
|
||||||
.ConfigureWebHostDefaults(webBuilder =>
|
.ConfigureWebHostDefaults(webBuilder =>
|
||||||
{
|
{
|
||||||
webBuilder.UseStartup<Startup>();
|
webBuilder.UseStartup<Startup>()
|
||||||
|
.UseConfiguration(configuration)
|
||||||
|
.UseSerilog();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (useWindowsService)
|
||||||
|
builder.UseWindowsService();
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,48 +1,80 @@
|
||||||
|
using AutoMapper;
|
||||||
|
using IdentityServer.Api.Swagger;
|
||||||
|
using IdentityServer.Application;
|
||||||
|
using IdentityServer.Domain.Data;
|
||||||
|
using MediatR;
|
||||||
|
using MediatR.Pipeline;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System.Reflection;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace IdentityServer.Api
|
namespace IdentityServer.Api
|
||||||
{
|
{
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
|
||||||
public Startup(IConfiguration configuration)
|
public Startup(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
Configuration = configuration;
|
_configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IConfiguration Configuration { get; }
|
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to add services to the container.
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddControllers();
|
services.AddControllers()
|
||||||
|
.AddNewtonsoftJson(o => o.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc);
|
||||||
|
|
||||||
|
// MediatR
|
||||||
|
services.AddMediatR(GetMediatRAssemblies());
|
||||||
|
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(RequestPreProcessorBehavior<,>));
|
||||||
|
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(RequestPostProcessorBehavior<,>));
|
||||||
|
|
||||||
|
// AutoMapper
|
||||||
|
services.AddAutoMapper(
|
||||||
|
typeof(Application.Mappings.MappingProfile).Assembly);
|
||||||
|
|
||||||
|
// Swagger
|
||||||
|
services.AddSwagger();
|
||||||
|
|
||||||
|
// Data access
|
||||||
|
services.AddDataAccess();
|
||||||
|
|
||||||
|
// Application
|
||||||
|
services.AddApplicationServices();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Assembly[] GetMediatRAssemblies()
|
||||||
|
{
|
||||||
|
var assembly = typeof(Application.Commands.AuthenticateUser).Assembly;
|
||||||
|
return new Assembly[] { assembly };
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
{
|
{
|
||||||
|
// global cors policy
|
||||||
|
app.UseCors(x => x
|
||||||
|
.AllowAnyOrigin()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader());
|
||||||
|
|
||||||
if (env.IsDevelopment())
|
if (env.IsDevelopment())
|
||||||
{
|
{
|
||||||
app.UseDeveloperExceptionPage();
|
app.UseDeveloperExceptionPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints =>
|
||||||
{
|
{
|
||||||
endpoints.MapControllers();
|
endpoints.MapControllers();
|
||||||
});
|
});
|
||||||
|
app.ConfigureSwagger();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
using IdentityServer.Application.Commands;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace IdentityServer.Api.Swagger
|
||||||
|
{
|
||||||
|
public class DtoSchemaFilter : ISchemaFilter
|
||||||
|
{
|
||||||
|
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
|
||||||
|
{
|
||||||
|
var targetType = context.Type;
|
||||||
|
while (targetType != null)
|
||||||
|
{
|
||||||
|
if (typeof(ICommand).IsAssignableFrom(targetType))
|
||||||
|
{
|
||||||
|
foreach (var property in schema.Properties.ToList())
|
||||||
|
{
|
||||||
|
property.Value.ReadOnly = false;
|
||||||
|
|
||||||
|
switch (property.Key)
|
||||||
|
{
|
||||||
|
case "metadata":
|
||||||
|
schema.Properties.Remove(property.Key);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
targetType = targetType.DeclaringType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace IdentityServer.Api.Swagger
|
||||||
|
{
|
||||||
|
public class PathParamsOperationFilter : IOperationFilter
|
||||||
|
{
|
||||||
|
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||||
|
{
|
||||||
|
const string paramCaptureGroup = "param";
|
||||||
|
|
||||||
|
var openApiPathParameters = operation.Parameters.Where(param => param.In == ParameterLocation.Path).ToList();
|
||||||
|
var pathParamRegEx = $@"\{{(?<{paramCaptureGroup}>[^\}}]+)\}}";
|
||||||
|
|
||||||
|
if (openApiPathParameters.Any())
|
||||||
|
{
|
||||||
|
var pathParameterMatches = Regex.Matches(context.ApiDescription.RelativePath, pathParamRegEx, RegexOptions.Compiled);
|
||||||
|
var pathParameters = pathParameterMatches.Select(x => x.Groups[paramCaptureGroup].Value);
|
||||||
|
|
||||||
|
foreach (var openApiPathParameter in openApiPathParameters)
|
||||||
|
{
|
||||||
|
var correspondingPathParameter = pathParameters.FirstOrDefault(x =>
|
||||||
|
string.Equals(x, openApiPathParameter.Name, StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
|
||||||
|
if (correspondingPathParameter != null)
|
||||||
|
openApiPathParameter.Name = correspondingPathParameter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace IdentityServer.Api.Swagger
|
||||||
|
{
|
||||||
|
public static class SwaggerExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddSwagger(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddSwaggerGen(c =>
|
||||||
|
{
|
||||||
|
c.SwaggerDoc("v1",
|
||||||
|
new OpenApiInfo
|
||||||
|
{
|
||||||
|
Title = "NetworkResurrector API",
|
||||||
|
Version = "v1"
|
||||||
|
});
|
||||||
|
|
||||||
|
c.AddSecurityDefinition("Basic",
|
||||||
|
new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Description = @"JWT Authorization header using the Basic scheme. Enter 'Basic' [space] and then your token in the text input below. Example: 'Basic 12345abcdef'",
|
||||||
|
Name = "Authorization",
|
||||||
|
Scheme = "Basic",
|
||||||
|
Type = SecuritySchemeType.ApiKey
|
||||||
|
});
|
||||||
|
|
||||||
|
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Reference = new OpenApiReference
|
||||||
|
{
|
||||||
|
Type = ReferenceType.SecurityScheme,
|
||||||
|
Id = "Basic"
|
||||||
|
},
|
||||||
|
Scheme = "Basic",
|
||||||
|
Name = "Authorization",
|
||||||
|
In = ParameterLocation.Header
|
||||||
|
},
|
||||||
|
new List<string>()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
c.OperationFilter<PathParamsOperationFilter>();
|
||||||
|
c.SchemaFilter<DtoSchemaFilter>();
|
||||||
|
c.CustomSchemaIds(type => type.ToString());
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IApplicationBuilder ConfigureSwagger(this IApplicationBuilder applicationBuilder)
|
||||||
|
{
|
||||||
|
applicationBuilder.UseSwagger(c =>
|
||||||
|
{
|
||||||
|
c.PreSerializeFilters.Add((swagger, httpRequest) =>
|
||||||
|
{
|
||||||
|
var (host, basePath, scheme) = GetUrlComponents(httpRequest);
|
||||||
|
|
||||||
|
swagger.Servers = new List<OpenApiServer>
|
||||||
|
{
|
||||||
|
new OpenApiServer {Url = $"{scheme}://{host}{basePath}"}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
c.RouteTemplate = "swagger/{documentName}/swagger.json";
|
||||||
|
});
|
||||||
|
|
||||||
|
applicationBuilder.UseSwaggerUI(c =>
|
||||||
|
{
|
||||||
|
c.SwaggerEndpoint("v1/swagger.json", "Chatbot API");
|
||||||
|
c.RoutePrefix = $"swagger";
|
||||||
|
});
|
||||||
|
|
||||||
|
return applicationBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (string host, string basePath, string scheme) GetUrlComponents(HttpRequest request)
|
||||||
|
{
|
||||||
|
var host = ExtractHost(request);
|
||||||
|
var basePath = ExtractBasePath(request);
|
||||||
|
var scheme = ExtractScheme(request);
|
||||||
|
|
||||||
|
return (host, basePath, scheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ExtractHost(HttpRequest request)
|
||||||
|
{
|
||||||
|
if (request.Headers.ContainsKey("X-Forwarded-Host"))
|
||||||
|
return request.Headers["X-Forwarded-Host"].First();
|
||||||
|
|
||||||
|
return request.Host.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ExtractBasePath(HttpRequest request)
|
||||||
|
{
|
||||||
|
if (request.Headers.ContainsKey("X-Forwarded-PathBase"))
|
||||||
|
return request.Headers["X-Forwarded-PathBase"].First();
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ExtractScheme(HttpRequest request)
|
||||||
|
{
|
||||||
|
return request.Headers["X-Forwarded-Proto"].FirstOrDefault() ?? request.Scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue