diff --git a/devdocs/todo.txt b/devdocs/todo.txt index 5da3d6b6..70110ab2 100644 --- a/devdocs/todo.txt +++ b/devdocs/todo.txt @@ -11,29 +11,6 @@ UPDATE all the things before commencing work - https://github.com/domaindrivendev/Swashbuckle.AspNetCore#swashbuckleaspnetcoreannotations - - -2019-10-16 12:47:22.3600|ERROR|Microsoft.AspNetCore.Server.Kestrel|Connection id "0HLQIE5LC01UO", Request id "0HLQIE5LC01UO:00000003": -An unhandled exception was thrown by the application.=>System.InvalidOperationException: Endpoint AyaNova.Api.Controllers.WidgetController.ListWidgets (AyaNova) -contains authorization metadata, but a middleware was not found that supports authorization. -Configure your application startup by adding app.UseAuthorization() inside the call to Configure(..) in the application startup code. The call to app.UseAuthorization() must appear between app.UseRouting() and app.UseEndpoints(...). - at Microsoft.AspNetCore.Routing.EndpointMiddleware.ThrowMissingAuthMiddlewareException(Endpoint endpoint) - - - - 2019-10-16 12:45:37.5732|ERROR|Microsoft.AspNetCore.Server.Kestrel|Connection id "0HLQIE5LC01UI", Request id "0HLQIE5LC01UI:00000001": - An unhandled exception was thrown by the application.=>System.TypeLoadException: - Could not load type 'Microsoft.AspNetCore.Mvc.Internal.MvcAttributeRouteHandler' from assembly 'Microsoft.AspNetCore.Mvc.Core, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. - at Microsoft.AspNetCore.Mvc.Internal.MvcRouteTemplateResolver.ResolveMatchingTemplateRouteAsync(RouteData routeData) - - - - - - - - - - Need a sprint to get to a fully testable client with entry form, list and as much as possible all features from COMMON-* specs list Do the stuff in the Client todo first then back to the server as required. diff --git a/server/AyaNova/AyaNova.csproj b/server/AyaNova/AyaNova.csproj index 62178b27..42178ba8 100644 --- a/server/AyaNova/AyaNova.csproj +++ b/server/AyaNova/AyaNova.csproj @@ -32,18 +32,22 @@ - + + - - runtime; build; native; contentfiles; analyzers; buildtransitive - all + + runtime; build; native; contentfiles; analyzers; buildtransitive + all - + + + + + diff --git a/server/AyaNova/Controllers/ApiRootController.cs b/server/AyaNova/Controllers/ApiRootController.cs index d6dd29d2..dc74c239 100644 --- a/server/AyaNova/Controllers/ApiRootController.cs +++ b/server/AyaNova/Controllers/ApiRootController.cs @@ -11,9 +11,9 @@ namespace AyaNova.Api.Controllers /// /// Meta controller class /// + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/")] [AllowAnonymous] - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/")]//was [Route("api/v{version:apiVersion}/")] public class ApiMetaController : Controller { private readonly ApiServerState serverState; diff --git a/server/AyaNova/Controllers/AttachmentController.cs b/server/AyaNova/Controllers/AttachmentController.cs index 4e9189da..60cc2998 100644 --- a/server/AyaNova/Controllers/AttachmentController.cs +++ b/server/AyaNova/Controllers/AttachmentController.cs @@ -32,8 +32,8 @@ namespace AyaNova.Api.Controllers /// /// Attachment controller /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] [Authorize] public class AttachmentController : Controller diff --git a/server/AyaNova/Controllers/AuthController.cs b/server/AyaNova/Controllers/AuthController.cs index db59dfb2..7572f3c6 100644 --- a/server/AyaNova/Controllers/AuthController.cs +++ b/server/AyaNova/Controllers/AuthController.cs @@ -10,7 +10,6 @@ using System; using System.Threading.Tasks; using App.Metrics; using AyaNova.Biz; -using Microsoft.AspNetCore.Authorization; //required to inject configuration in constructor using Microsoft.Extensions.Configuration; @@ -20,10 +19,9 @@ namespace AyaNova.Api.Controllers /// /// Authentication controller /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] - [AllowAnonymous] public class AuthController : Controller { private readonly AyContext ct; diff --git a/server/AyaNova/Controllers/AyaEnumPickListController.cs b/server/AyaNova/Controllers/AyaEnumPickListController.cs index c6364b85..cd4a285b 100644 --- a/server/AyaNova/Controllers/AyaEnumPickListController.cs +++ b/server/AyaNova/Controllers/AyaEnumPickListController.cs @@ -15,8 +15,8 @@ namespace AyaNova.Api.Controllers /// /// Enum pick list controller /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] [Authorize] public class AyaEnumPickListController : Controller diff --git a/server/AyaNova/Controllers/AyaTypeController.cs b/server/AyaNova/Controllers/AyaTypeController.cs index 6bc1e616..3c5fdb73 100644 --- a/server/AyaNova/Controllers/AyaTypeController.cs +++ b/server/AyaNova/Controllers/AyaTypeController.cs @@ -15,8 +15,8 @@ namespace AyaNova.Api.Controllers /// /// AyaType list controller /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] [Authorize] public class AyaTypeController : Controller diff --git a/server/AyaNova/Controllers/BackupController.cs b/server/AyaNova/Controllers/BackupController.cs index b0be0732..90b4f20e 100644 --- a/server/AyaNova/Controllers/BackupController.cs +++ b/server/AyaNova/Controllers/BackupController.cs @@ -46,8 +46,8 @@ namespace AyaNova.Api.Controllers /// and triggering a restore from backup /// /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] [Authorize] public class BackupController : Controller diff --git a/server/AyaNova/Controllers/DataFilterController.cs b/server/AyaNova/Controllers/DataFilterController.cs index 07990ae6..f549bdc9 100644 --- a/server/AyaNova/Controllers/DataFilterController.cs +++ b/server/AyaNova/Controllers/DataFilterController.cs @@ -19,8 +19,8 @@ namespace AyaNova.Api.Controllers /// /// /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] [Authorize] public class DataFilterController : Controller diff --git a/server/AyaNova/Controllers/EventLogController.cs b/server/AyaNova/Controllers/EventLogController.cs index f23d8616..f9ae1117 100644 --- a/server/AyaNova/Controllers/EventLogController.cs +++ b/server/AyaNova/Controllers/EventLogController.cs @@ -19,8 +19,8 @@ namespace AyaNova.Api.Controllers /// /// Log files controller /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Authorize] public class EventLogController : Controller { diff --git a/server/AyaNova/Controllers/FormCustomController.cs b/server/AyaNova/Controllers/FormCustomController.cs index 468d0c92..1e621e3f 100644 --- a/server/AyaNova/Controllers/FormCustomController.cs +++ b/server/AyaNova/Controllers/FormCustomController.cs @@ -19,8 +19,8 @@ namespace AyaNova.Api.Controllers /// /// /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] [Authorize] public class FormCustomController : Controller diff --git a/server/AyaNova/Controllers/ImportAyaNova7Controller.cs b/server/AyaNova/Controllers/ImportAyaNova7Controller.cs index 24299593..be990765 100644 --- a/server/AyaNova/Controllers/ImportAyaNova7Controller.cs +++ b/server/AyaNova/Controllers/ImportAyaNova7Controller.cs @@ -29,8 +29,8 @@ namespace AyaNova.Api.Controllers /// /// Import AyaNova 7 data controller /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] [Authorize] public class ImportAyaNova7Controller : Controller diff --git a/server/AyaNova/Controllers/JobOperationsController.cs b/server/AyaNova/Controllers/JobOperationsController.cs index dc1cb2dd..4dd8b621 100644 --- a/server/AyaNova/Controllers/JobOperationsController.cs +++ b/server/AyaNova/Controllers/JobOperationsController.cs @@ -17,8 +17,8 @@ namespace AyaNova.Api.Controllers /// /// JobOperations controller /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] [Authorize] public class JobOperationsController : Controller diff --git a/server/AyaNova/Controllers/LicenseController.cs b/server/AyaNova/Controllers/LicenseController.cs index ebbff73f..811ae95c 100644 --- a/server/AyaNova/Controllers/LicenseController.cs +++ b/server/AyaNova/Controllers/LicenseController.cs @@ -16,8 +16,8 @@ namespace AyaNova.Api.Controllers /// /// License route /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] [Authorize] public class LicenseController : Controller diff --git a/server/AyaNova/Controllers/LocaleController.cs b/server/AyaNova/Controllers/LocaleController.cs index 2825ee62..43f3306e 100644 --- a/server/AyaNova/Controllers/LocaleController.cs +++ b/server/AyaNova/Controllers/LocaleController.cs @@ -23,8 +23,8 @@ namespace AyaNova.Api.Controllers /// /// Localized text controller /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] [Authorize] public class LocaleController : Controller diff --git a/server/AyaNova/Controllers/LogFilesController.cs b/server/AyaNova/Controllers/LogFilesController.cs index 0c4d4d96..71d19716 100644 --- a/server/AyaNova/Controllers/LogFilesController.cs +++ b/server/AyaNova/Controllers/LogFilesController.cs @@ -16,8 +16,8 @@ namespace AyaNova.Api.Controllers /// /// Log files controller /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] //[Produces("application/json")] [Authorize] public class LogFilesController : Controller diff --git a/server/AyaNova/Controllers/MetricsController.cs b/server/AyaNova/Controllers/MetricsController.cs index 4024350f..e1f87d2d 100644 --- a/server/AyaNova/Controllers/MetricsController.cs +++ b/server/AyaNova/Controllers/MetricsController.cs @@ -18,8 +18,8 @@ namespace AyaNova.Api.Controllers /// /// Log files controller /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Authorize] public class MetricsController : Controller { diff --git a/server/AyaNova/Controllers/SearchController.cs b/server/AyaNova/Controllers/SearchController.cs index ffa5bf90..f991e561 100644 --- a/server/AyaNova/Controllers/SearchController.cs +++ b/server/AyaNova/Controllers/SearchController.cs @@ -19,8 +19,8 @@ namespace AyaNova.Api.Controllers /// /// Search /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] [Authorize] public class SearchController : Controller diff --git a/server/AyaNova/Controllers/ServerStateController.cs b/server/AyaNova/Controllers/ServerStateController.cs index 06b49c81..ced534cc 100644 --- a/server/AyaNova/Controllers/ServerStateController.cs +++ b/server/AyaNova/Controllers/ServerStateController.cs @@ -15,8 +15,8 @@ namespace AyaNova.Api.Controllers /// /// Server state controller /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] public class ServerStateController : Controller { diff --git a/server/AyaNova/Controllers/TagListController.cs b/server/AyaNova/Controllers/TagListController.cs index 4659cb5f..07255035 100644 --- a/server/AyaNova/Controllers/TagListController.cs +++ b/server/AyaNova/Controllers/TagListController.cs @@ -15,8 +15,8 @@ namespace AyaNova.Api.Controllers /// /// Enum pick list controller /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] [Authorize] public class TagListController : Controller diff --git a/server/AyaNova/Controllers/TrialController.cs b/server/AyaNova/Controllers/TrialController.cs index f850dce5..e8cc9906 100644 --- a/server/AyaNova/Controllers/TrialController.cs +++ b/server/AyaNova/Controllers/TrialController.cs @@ -13,8 +13,8 @@ namespace AyaNova.Api.Controllers /// ///Test controller class used during development /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] [Authorize] public class TrialController : Controller diff --git a/server/AyaNova/Controllers/UserController.cs b/server/AyaNova/Controllers/UserController.cs index 70dee427..5f9ada8d 100644 --- a/server/AyaNova/Controllers/UserController.cs +++ b/server/AyaNova/Controllers/UserController.cs @@ -19,8 +19,8 @@ namespace AyaNova.Api.Controllers /// /// User /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] [Authorize] public class UserController : Controller diff --git a/server/AyaNova/Controllers/UserOptionsController.cs b/server/AyaNova/Controllers/UserOptionsController.cs index 97158471..10285549 100644 --- a/server/AyaNova/Controllers/UserOptionsController.cs +++ b/server/AyaNova/Controllers/UserOptionsController.cs @@ -19,8 +19,8 @@ namespace AyaNova.Api.Controllers /// /// UserOptions /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] [Authorize] public class UserOptionsController : Controller diff --git a/server/AyaNova/Controllers/WidgetController.cs b/server/AyaNova/Controllers/WidgetController.cs index b17f3527..80619579 100644 --- a/server/AyaNova/Controllers/WidgetController.cs +++ b/server/AyaNova/Controllers/WidgetController.cs @@ -22,8 +22,8 @@ namespace AyaNova.Api.Controllers /// /// Sample controller class used during development for testing purposes /// - //SWASHBUCKLETEST [ApiVersion("8.0")] - [Route("api/v8/[controller]")]//was [Route("api/v{version:apiVersion}/[controller]")] + [ApiVersion("8.0")] + [Route("api/v{version:apiVersion}/[controller]")] [Produces("application/json")] [Authorize] public class WidgetController : Controller diff --git a/server/AyaNova/Program.cs b/server/AyaNova/Program.cs index 3d317698..f1e22136 100644 --- a/server/AyaNova/Program.cs +++ b/server/AyaNova/Program.cs @@ -207,45 +207,45 @@ namespace AyaNova .UseUrls(ServerBootConfig.AYANOVA_USE_URLS)//default port and urls, set first can be overridden by any later setting here .UseConfiguration(configuration)//support command line override of port (dotnet run urls=http://*:8081) .UseIISIntegration()//support IIS integration just in case, it appears here to override prior settings if necessary (port) - // .ConfigureMetricsWithDefaults(builder => - // { - // if (ServerBootConfig.AYANOVA_METRICS_USE_INFLUXDB) - // { - // builder.Report.ToInfluxDb( - // options => - // { + .ConfigureMetricsWithDefaults(builder => + { + if (ServerBootConfig.AYANOVA_METRICS_USE_INFLUXDB) + { + builder.Report.ToInfluxDb( + options => + { - // options.InfluxDb.BaseUri = new Uri(ServerBootConfig.AYANOVA_METRICS_INFLUXDB_BASEURL); - // options.InfluxDb.Database = ServerBootConfig.AYANOVA_METRICS_INFLUXDB_DBNAME; - // if (!string.IsNullOrWhiteSpace(ServerBootConfig.AYANOVA_METRICS_INFLUXDB_CONSISTENCY)) - // { - // options.InfluxDb.Consistenency = ServerBootConfig.AYANOVA_METRICS_INFLUXDB_CONSISTENCY; - // } - // options.InfluxDb.UserName = ServerBootConfig.AYANOVA_METRICS_INFLUXDB_USERNAME; - // options.InfluxDb.Password = ServerBootConfig.AYANOVA_METRICS_INFLUXDB_PASSWORD; - // if (!string.IsNullOrWhiteSpace(ServerBootConfig.AYANOVA_METRICS_INFLUXDB_RETENTION_POLICY)) - // { - // options.InfluxDb.RetentionPolicy = ServerBootConfig.AYANOVA_METRICS_INFLUXDB_RETENTION_POLICY; - // } + options.InfluxDb.BaseUri = new Uri(ServerBootConfig.AYANOVA_METRICS_INFLUXDB_BASEURL); + options.InfluxDb.Database = ServerBootConfig.AYANOVA_METRICS_INFLUXDB_DBNAME; + if (!string.IsNullOrWhiteSpace(ServerBootConfig.AYANOVA_METRICS_INFLUXDB_CONSISTENCY)) + { + options.InfluxDb.Consistenency = ServerBootConfig.AYANOVA_METRICS_INFLUXDB_CONSISTENCY; + } + options.InfluxDb.UserName = ServerBootConfig.AYANOVA_METRICS_INFLUXDB_USERNAME; + options.InfluxDb.Password = ServerBootConfig.AYANOVA_METRICS_INFLUXDB_PASSWORD; + if (!string.IsNullOrWhiteSpace(ServerBootConfig.AYANOVA_METRICS_INFLUXDB_RETENTION_POLICY)) + { + options.InfluxDb.RetentionPolicy = ServerBootConfig.AYANOVA_METRICS_INFLUXDB_RETENTION_POLICY; + } - // options.InfluxDb.CreateDataBaseIfNotExists = true; - // options.HttpPolicy.BackoffPeriod = TimeSpan.FromSeconds(30); - // options.HttpPolicy.FailuresBeforeBackoff = 5; - // options.HttpPolicy.Timeout = TimeSpan.FromSeconds(10); - // //options.MetricsOutputFormatter = new App.Metrics.Formatters.Json.MetricsJsonOutputFormatter(); - // //options.Filter = filter; - // options.FlushInterval = TimeSpan.FromSeconds(20); - // }); - // } + options.InfluxDb.CreateDataBaseIfNotExists = true; + options.HttpPolicy.BackoffPeriod = TimeSpan.FromSeconds(30); + options.HttpPolicy.FailuresBeforeBackoff = 5; + options.HttpPolicy.Timeout = TimeSpan.FromSeconds(10); + //options.MetricsOutputFormatter = new App.Metrics.Formatters.Json.MetricsJsonOutputFormatter(); + //options.Filter = filter; + options.FlushInterval = TimeSpan.FromSeconds(20); + }); + } - // }) - // .UseMetricsEndpoints(opt => - // { - // opt.EnvironmentInfoEndpointEnabled = false; - // opt.MetricsEndpointEnabled = false; - // opt.MetricsTextEndpointEnabled = false; - // }) - // .UseMetrics() + }) + .UseMetricsEndpoints(opt => + { + opt.EnvironmentInfoEndpointEnabled = false; + opt.MetricsEndpointEnabled = false; + opt.MetricsTextEndpointEnabled = false; + }) + .UseMetrics() .UseStartup() .ConfigureLogging((context, logging) => { diff --git a/server/AyaNova/Startup.cs b/server/AyaNova/Startup.cs index 0d21506a..2dad823f 100644 --- a/server/AyaNova/Startup.cs +++ b/server/AyaNova/Startup.cs @@ -62,31 +62,36 @@ namespace AyaNova { _log.LogDebug("BOOT: initializing services..."); - //dotnet 3.x added this wasn't here before - services.AddControllers(); - services.AddSwaggerGen(c => - { - c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" }); - }); //Server state service for shutting people out of api _log.LogDebug("BOOT: init ApiServerState service"); services.AddSingleton(new AyaNova.Api.ControllerHelpers.ApiServerState()); + //Init controllers + _log.LogDebug("BOOT: init controllers"); + var MvcBuilder = services.AddControllers(config => + { + config.Filters.Add(new AyaNova.Api.ControllerHelpers.ApiCustomExceptionFilter(AyaNova.Util.ApplicationLogging.LoggerFactory)); + }); + + _log.LogDebug("BOOT: init JSON"); + MvcBuilder.AddNewtonsoftJson(options => + { + options.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc; + }); + + //2019-10-17 METRICS will not work just yet with .netcore 3.1 see here https://github.com/AppMetrics/AppMetrics/issues/480 + //awaiting a new release from them + //_log.LogDebug("BOOT: init Metrics service"); + //MvcBuilder.AddMetrics(); - //dotnet 3 commented this out, new project doesn't have it - //Init mvc - // _log.LogDebug("BOOT: init MVC Core service"); - // var mvc = services.AddMvcCore(); - // _log.LogDebug("BOOT: add json service"); - // mvc.AddNewtonsoftJson(); // add the versioned api explorer, which also adds IApiVersionDescriptionProvider service // note: the specified format code will format the version as "'v'major[.minor][-status]" _log.LogDebug("BOOT: init ApiExplorer service"); - // services.AddVersionedApiExplorer(o => o.GroupNameFormat = "'v'VVV"); + services.AddVersionedApiExplorer(o => o.GroupNameFormat = "'v'VVV"); _log.LogDebug("BOOT: ensuring user and backup folders exist and are separate locations..."); FileUtil.EnsureUserAndUtilityFoldersExistAndAreNotIdentical(_hostingEnvironment.ContentRootPath); @@ -143,46 +148,31 @@ namespace AyaNova #endregion _log.LogDebug("BOOT: init ApiVersioning service"); - // services - // .AddApiVersioning(options => - // { - // options.AssumeDefaultVersionWhenUnspecified = true; - // options.DefaultApiVersion = Microsoft.AspNetCore.Mvc.ApiVersion.Parse("8.0"); - // options.ReportApiVersions = true; - // }); + // services.AddApiVersioning(o => o.ReportApiVersions = true); + services + .AddApiVersioning(options => + { + options.AssumeDefaultVersionWhenUnspecified = true; + options.DefaultApiVersion = Microsoft.AspNetCore.Mvc.ApiVersion.Parse("8.0"); + options.ReportApiVersions = true; + }); - //v3 commented out to try to figure out why the swagger docs aren't generating and may be superfluous - // // Add service and create Policy with options - // _log.LogDebug("BOOT: init CORS service"); - // services.AddCors(options => - // { - // options.AddPolicy("CorsPolicy", - // builder => builder.AllowAnyOrigin() - // .AllowAnyMethod() - // .AllowAnyHeader() - // //.AllowCredentials() - // ); - // }); + // Add service and create Policy with options + _log.LogDebug("BOOT: init CORS service"); + services.AddCors(options => + { + options.AddPolicy("CorsPolicy", + builder => builder.AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader() + //.AllowCredentials() + ); + }); - _log.LogDebug("BOOT: init MVC service"); - _log.LogDebug("BOOT: init Metrics service"); - // services.AddMvc(config => - // { - // //was this but needed logging, not certain about the new way of adding so keeping this in case it all goes sideways in testing - // //config.Filters.Add(typeof(AyaNova.Api.ControllerHelpers.ApiCustomExceptionFilter)); - // config.Filters.Add(new AyaNova.Api.ControllerHelpers.ApiCustomExceptionFilter(AyaNova.Util.ApplicationLogging.LoggerFactory)); - - // }).AddMetrics().AddJsonOptions(options => - // { - // //2019-10-15 - removed this due to fuckery after update, is it required??? Not sure at this point - // //if metrics have wrong dates then it's important I guess - // //options.JsonSerializerOptions.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc; - // }); - #region Swagger //https://docs.microsoft.com/en-us/aspnet/core/tutorials/web-api-help-pages-using-swagger?tabs=visual-studio-code @@ -190,112 +180,73 @@ namespace AyaNova //https://github.com/domaindrivendev/Swashbuckle.AspNetCore _log.LogDebug("BOOT: init API explorer service"); - // services.AddSwaggerGen(c => - // { - // c.SwaggerDoc("v8", new OpenApiInfo { Title = "My API", Version = "v8" }); - // c.OperationFilter(); + services.AddSwaggerGen( + c => + { + // resolve the IApiVersionDescriptionProvider service + // note: that we have to build a temporary service provider here because one has not been created yet + var provider = services.BuildServiceProvider().GetRequiredService(); - // }); - // services.AddSwaggerGen( - // c => - // { + // add a swagger document for each discovered API version + // note: you might choose to skip or document deprecated API versions differently + foreach (var description in provider.ApiVersionDescriptions) + { + c.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description)); + } + // add a custom operation filter which sets default values + //Removed because will no longer compile the SwaggerDefaultValues but may be needed, not sure it's all a bit muddled + // c.OperationFilter(); - // c.DocInclusionPredicate((docName, apiDesc) => - // { - // if (!apiDesc.TryGetMethodInfo(out MethodInfo methodInfo)) return false; - - // // Get the MapToApiVersion attributes of the action - // var mapApiVersions = methodInfo - // .GetCustomAttributes(true) - // .OfType() - // .SelectMany(attr => attr.Versions); - - // //if it contains MapToApiVersion attributes, then we should check those as the ApiVersion ones are ignored - // if (mapApiVersions.Any() && mapApiVersions.Any(v => $"v{v.ToString()}" == docName)) - // return true; - - // // Get the ApiVersion attributes of the controller - // var versions = methodInfo.DeclaringType - // .GetCustomAttributes(true) - // .OfType() - // .SelectMany(attr => attr.Versions); - - // return versions.Any(v => $"v{v.ToString()}" == docName); - // }); + // integrate xml comments + c.IncludeXmlComments(XmlCommentsFilePath); - // // resolve the IApiVersionDescriptionProvider service - // // note: that we have to build a temporary service provider here because one has not been created yet - // var provider = services.BuildServiceProvider().GetRequiredService(); + //2019-10-15 - Removed this because apikeyscheme is no longer recognized and it appears it *may* not be necessary... TWT + //If I have any issues with bearer tokens in swagger then this is probably necessary but in a new way + //this is required to allow authentication when testing secure routes via swagger UI + // c.AddSecurityDefinition("Bearer", new ApiKeyScheme + // { + // Description = "JWT Authorization header using the Bearer scheme. Get your token by logging in via the Auth route then enter it here with the \"Bearer \" prefix. Example: \"Bearer {token}\"", + // Name = "Authorization", + // In = "header", + // Type = "apiKey" - // // add a swagger document for each discovered API version - // // note: you might choose to skip or document deprecated API versions differently - // foreach (var description in provider.ApiVersionDescriptions) - // { - // c.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description)); - // } - - // // add a custom operation filter which sets default values - // // c.OperationFilter(); - - // //test filter WTF? - // //c.OperationFilter(); - - // // integrate xml comments - // c.IncludeXmlComments(XmlCommentsFilePath); - - - - // // //2019-10-15 - Removed this because apikeyscheme is no longer recognized and it appears it *may* not be necessary... TWT - // // //If I have any issues with bearer tokens in swagger then this is probably necessary but in a new way - // // //this is required to allow authentication when testing secure routes via swagger UI - // // c.AddSecurityDefinition("Bearer", new ApiKeyScheme - // // { - // // Description = "JWT Authorization header using the Bearer scheme. Get your token by logging in via the Auth route then enter it here with the \"Bearer \" prefix. Example: \"Bearer {token}\"", - // // Name = "Authorization", - // // In = "header", - // // Type = "apiKey" - - // // }); + // }); - // //Obsolete way - // // c.AddSecurityRequirement(new System.Collections.Generic.Dictionary> - // // { - // // { "Bearer", new string[] { } } - // // }); + //Obsolete way + // c.AddSecurityRequirement(new System.Collections.Generic.Dictionary> + // { + // { "Bearer", new string[] { } } + // }); - // //https://stackoverflow.com/questions/56234504/migrating-to-swashbuckle-aspnetcore-version-5 - // //First we define the security scheme - // c.AddSecurityDefinition("Bearer", //Name the security scheme - // new OpenApiSecurityScheme - // { - // Description = "JWT Authorization header using the Bearer scheme.", - // Type = SecuritySchemeType.Http, //We set the scheme type to http since we're using bearer authentication - // Scheme = "bearer" //The name of the HTTP Authorization scheme to be used in the Authorization header. In this case "bearer". - // }); + //https://stackoverflow.com/questions/56234504/migrating-to-swashbuckle-aspnetcore-version-5 + //First we define the security scheme + c.AddSecurityDefinition("Bearer", //Name the security scheme + new OpenApiSecurityScheme + { + Description = "JWT Authorization header using the Bearer scheme.", + Type = SecuritySchemeType.Http, //We set the scheme type to http since we're using bearer authentication + Scheme = "bearer" //The name of the HTTP Authorization scheme to be used in the Authorization header. In this case "bearer". + }); - // c.AddSecurityRequirement(new OpenApiSecurityRequirement{ - // { - // new OpenApiSecurityScheme{ - // Reference = new OpenApiReference{ - // Id = "Bearer", //The name of the previously defined security scheme. - // Type = ReferenceType.SecurityScheme - // } - // },new List() - // } - // }); + c.AddSecurityRequirement(new OpenApiSecurityRequirement{ + { + new OpenApiSecurityScheme{ + Reference = new OpenApiReference{ + Id = "Bearer", //The name of the previously defined security scheme. + Type = ReferenceType.SecurityScheme + } + },new List() + } + }); - // //https://github.com/domaindrivendev/Swashbuckle.AspNetCore - // //ARGGHHHHHHHH!!!!! - - - // }); + }); #endregion @@ -367,20 +318,14 @@ namespace AyaNova // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IWebHostEnvironment env, - AyContext dbContext, AyaNova.Api.ControllerHelpers.ApiServerState apiServerState, IServiceProvider serviceProvider) + AyContext dbContext, IApiVersionDescriptionProvider provider, AyaNova.Api.ControllerHelpers.ApiServerState apiServerState, IServiceProvider serviceProvider) { - //This was in constructor right after dbcontext: IApiVersionDescriptionProvider provider, _log.LogDebug("BOOT: configuring request pipeline..."); - //dotnet3 test added if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } - - //This is in new templates generated for webapi but it errors out for me so removing it for now - // app.UseHttpsRedirection(); - //Store a reference to the dependency injection service for static classes ServiceProviderProvider.Provider = app.ApplicationServices; @@ -394,15 +339,26 @@ namespace AyaNova _log.LogDebug("BOOT: pipeline - static files"); app.UseDefaultFiles(); app.UseStaticFiles(); - + //Might need the following if the page doesn't update in the client properly + //however the vue build process will automatically uniquify each build file names so maybe not required + // app.UseStaticFiles(new StaticFileOptions + // { + // OnPrepareResponse = context => + // { + // if (context.File.Name == "index.html") + // { + // context.Context.Response.Headers.Add("Cache-Control", "no-cache, no-store"); + // context.Context.Response.Headers.Add("Expires", "-1"); + // } + // } + // }); #endregion _log.LogDebug("BOOT: pipeline - ROUTING"); app.UseRouting();//this wasn't here for 2.2 but added for 3.0, needs to come before the stuff after - //v3test - // _log.LogDebug("BOOT: pipeline - CORS"); - // app.UseCors("CorsPolicy"); + _log.LogDebug("BOOT: pipeline - CORS"); + app.UseCors("CorsPolicy"); #region AUTH / ROLES @@ -413,6 +369,7 @@ namespace AyaNova _log.LogDebug("BOOT: pipeline - authorization"); app.UseAuthorization(); + //Custom middleware to get user roles and put them into the request so //they can be authorized in routes. app.Use(async (context, next) => @@ -444,46 +401,33 @@ namespace AyaNova #endregion - //According to https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-2.2&tabs=visual-studio#migrate-startupconfigure _log.LogDebug("BOOT: pipeline - ENDPOINTS"); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); - #region SWAGGER _log.LogDebug("BOOT: pipeline - api explorer"); - // // Enable middleware to serve generated Swagger as a JSON endpoint. - // app.UseSwagger(); - - // app.UseSwaggerUI(c => - // { - // // build a swagger endpoint for each discovered API version - // foreach (var description in provider.ApiVersionDescriptions) - // { - // c.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant()); - // } - - // //clean up the swagger explorer UI page and remove the branding - // //via our own css - // //NOTE: this broke when updated to v2.x of swagger and it can be fixed according to docs: - // //https://github.com/domaindrivendev/Swashbuckle.AspNetCore#inject-custom-css - // // c.InjectStylesheet("/api/sw.css"); - - // c.DefaultModelsExpandDepth(-1); - // c.DocumentTitle = "AyaNova API explorer"; - // c.RoutePrefix = "api-docs"; - - // }); - - app.UseSwagger(); + // Enable middleware to serve generated Swagger as a JSON endpoint. + app.UseSwagger(); app.UseSwaggerUI(c => { - c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); - c.DefaultModelsExpandDepth(-1); + // build a swagger endpoint for each discovered API version + foreach (var description in provider.ApiVersionDescriptions) + { + c.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant()); + } + + //clean up the swagger explorer UI page and remove the branding + //via our own css + //NOTE: this broke when updated to v2.x of swagger and it can be fixed according to docs: + //https://github.com/domaindrivendev/Swashbuckle.AspNetCore#inject-custom-css + // c.InjectStylesheet("/api/sw.css"); + + c.DefaultModelsExpandDepth(-1); c.DocumentTitle = "AyaNova API explorer"; c.RoutePrefix = "api-docs"; }); @@ -494,6 +438,15 @@ namespace AyaNova + //According to https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-2.2&tabs=visual-studio#migrate-startupconfigure + //replace use mvc with use endpoints + // //USE MVC + // _log.LogDebug("BOOT: pipeline - MVC"); + // app.UseMvc(); + // _log.LogDebug("BOOT: pipeline - ENDPOINTS"); + // app.UseEndpoints(endpoints => { + // endpoints.MapControllers(); + // }); // ****************************************************************** // ******************** TESTING WIPE DB ***************************** @@ -582,33 +535,33 @@ namespace AyaNova #region Swagger and API Versioning utilities - // static string XmlCommentsFilePath - // { - // get - // { - // //Obsolete, used new method: https://developers.de/blogs/holger_vetter/archive/2017/06/30/swagger-includexmlcomments-platformservices-obsolete-replacement.aspx - // //var basePath = PlatformServices.Default.Application.ApplicationBasePath; - // var basePath = AppContext.BaseDirectory; - // var fileName = typeof(Startup).GetTypeInfo().Assembly.GetName().Name + ".xml"; - // return Path.Combine(basePath, fileName); - // } - // } + static string XmlCommentsFilePath + { + get + { + //Obsolete, used new method: https://developers.de/blogs/holger_vetter/archive/2017/06/30/swagger-includexmlcomments-platformservices-obsolete-replacement.aspx + //var basePath = PlatformServices.Default.Application.ApplicationBasePath; + var basePath = AppContext.BaseDirectory; + var fileName = typeof(Startup).GetTypeInfo().Assembly.GetName().Name + ".xml"; + return Path.Combine(basePath, fileName); + } + } - // static Microsoft.OpenApi.Models.OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description) - // { - // var info = new Microsoft.OpenApi.Models.OpenApiInfo() - // { - // Title = $"AyaNova API {description.ApiVersion}", - // Version = description.ApiVersion.ToString() - // }; + static Microsoft.OpenApi.Models.OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description) + { + var info = new Microsoft.OpenApi.Models.OpenApiInfo() + { + Title = $"AyaNova API {description.ApiVersion}", + Version = description.ApiVersion.ToString() + }; - // if (description.IsDeprecated) - // { - // info.Description += " This API version has been deprecated."; - // } + if (description.IsDeprecated) + { + info.Description += " This API version has been deprecated."; + } - // return info; - // } + return info; + } #endregion diff --git a/server/AyaNova/SwaggerDefaultValues.cs b/server/AyaNova/SwaggerDefaultValues.cs index 56525ed1..eff78291 100644 --- a/server/AyaNova/SwaggerDefaultValues.cs +++ b/server/AyaNova/SwaggerDefaultValues.cs @@ -1,69 +1,47 @@ -namespace AyaNova -{ - using Microsoft.OpenApi.Models; - using Swashbuckle.AspNetCore.SwaggerGen; - using System.Linq; -using Microsoft.AspNetCore.Authorization; - - //https://github.com/domaindrivendev/Swashbuckle.AspNetCore/releases/tag/v5.0.0-rc3 - - /// - /// Represents the Swagger/Swashbuckle operation filter used to document the implicit API version parameter. - /// - /// This is only required due to bugs in the . - /// Once they are fixed and published, this class can be removed. - public class SwaggerDefaultValues : IOperationFilter - { - /// - /// Applies the filter to the specified operation using the given context. - /// - /// The operation to apply the filter to. - /// The current operation filter context. - public void Apply(OpenApiOperation operation, OperationFilterContext context) - { - // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/412 - // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/pull/413 - foreach (var parameter in operation.Parameters) - { - var description = context.ApiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name); - var routeInfo = description.RouteInfo; - - if (parameter.Description == null) - { - parameter.Description = description.ModelMetadata?.Description; - } - - if (routeInfo == null) - { - continue; - } - - // if (parameter.Default == null) - // { - // parameter.Default = routeInfo.DefaultValue; - // } - - parameter.Required |= !routeInfo.IsOptional; - } - } - } +// namespace AyaNova +// { +// using Swashbuckle.AspNetCore.SwaggerGen; +// using System.Linq; +// /// +// /// Represents the Swagger/Swashbuckle operation filter used to document the implicit API version parameter. +// /// +// /// This is only required due to bugs in the . +// /// Once they are fixed and published, this class can be removed. +// public class SwaggerDefaultValues : IOperationFilter +// { +// /// +// /// Applies the filter to the specified operation using the given context. +// /// +// /// The operation to apply the filter to. +// /// The current operation filter context. +// public void Apply( Operation operation, OperationFilterContext context ) +// { +// // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/412 +// // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/pull/413 +// foreach ( var parameter in operation.Parameters.OfType() ) +// { +// var description = context.ApiDescription.ParameterDescriptions.First( p => p.Name == parameter.Name ); +// var routeInfo = description.RouteInfo; +// if ( parameter.Description == null ) +// { +// parameter.Description = description.ModelMetadata?.Description; +// } -// AuthResponsesOperationFilter.cs -public class AuthResponsesOperationFilter : IOperationFilter -{ - public void Apply(OpenApiOperation operation, OperationFilterContext context) - { - var authAttributes = context.MethodInfo.DeclaringType.GetCustomAttributes(true) - .Union(context.MethodInfo.GetCustomAttributes(true)) - .OfType(); +// if ( routeInfo == null ) +// { +// continue; +// } - if (authAttributes.Any()) - operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" }); - } -} - -} +// if ( parameter.Default == null ) +// { +// parameter.Default = routeInfo.DefaultValue; +// } +// parameter.Required |= !routeInfo.IsOptional; +// } +// } +// } +// } \ No newline at end of file