| | | 1 | | using ArturRios.Util.WebApi.Middleware; |
| | | 2 | | using ArturRios.Util.WebApi.Security.Middleware; |
| | | 3 | | using Microsoft.AspNetCore.Builder; |
| | | 4 | | using Microsoft.Extensions.DependencyInjection; |
| | | 5 | | using Swashbuckle.AspNetCore.Swagger; |
| | | 6 | | using TokenAuthenticationOptions = ArturRios.Util.WebApi.Security.Configuration.AuthenticationOptions; |
| | | 7 | | |
| | | 8 | | namespace ArturRios.Util.WebApi.Configuration; |
| | | 9 | | |
| | | 10 | | /// <summary>Pipeline-side steps of the standard web API setup. <see cref="WebApiStartup"/> runs them in order, and |
| | | 11 | | /// each one can be used on its own with a plain <see cref="WebApplication"/>.</summary> |
| | | 12 | | public static class ApplicationBuilderExtensions |
| | | 13 | | { |
| | | 14 | | /// <param name="app">The application builder.</param> |
| | | 15 | | extension(IApplicationBuilder app) |
| | | 16 | | { |
| | | 17 | | /// <summary>Adds the standard middlewares, in order: ASP.NET Core's forwarded headers (a no-op until |
| | | 18 | | /// <c>ForwardedHeadersOptions</c> is configured, so the client IP behind a trusted proxy is the real one), |
| | | 19 | | /// <see cref="TraceActivityMiddleware"/>, |
| | | 20 | | /// <see cref="ExceptionMiddleware"/>, Swagger (see <see cref="UseWebApiSwagger"/>), CORS when |
| | | 21 | | /// <paramref name="corsPolicy"/> is given, then <see cref="AuthenticationMiddleware"/> when token authenticatio |
| | | 22 | | /// was registered with <c>AddTokenAuthentication</c>. Swagger and CORS come before authentication, so the |
| | | 23 | | /// Swagger UI and CORS preflight requests are never rejected for lacking a token.</summary> |
| | | 24 | | /// <param name="corsPolicy">The name of a CORS policy registered with <c>AddCors</c>, or <see langword="null"/> |
| | | 25 | | /// for no CORS.</param> |
| | | 26 | | /// <returns>The same <paramref name="app"/> instance, for chaining.</returns> |
| | | 27 | | public IApplicationBuilder UseStandardMiddlewares(string? corsPolicy = null) |
| | | 28 | | { |
| | 20 | 29 | | app.UseForwardedHeaders(); |
| | 20 | 30 | | app.UseMiddleware<TraceActivityMiddleware>(); |
| | 20 | 31 | | app.UseMiddleware<ExceptionMiddleware>(); |
| | 20 | 32 | | app.UseWebApiSwagger(); |
| | | 33 | | |
| | 20 | 34 | | if (!string.IsNullOrWhiteSpace(corsPolicy)) |
| | | 35 | | { |
| | 1 | 36 | | app.UseCors(corsPolicy); |
| | | 37 | | } |
| | | 38 | | |
| | 20 | 39 | | if (app.ApplicationServices.GetService<TokenAuthenticationOptions>() is not null) |
| | | 40 | | { |
| | 3 | 41 | | app.UseMiddleware<AuthenticationMiddleware>(); |
| | | 42 | | } |
| | | 43 | | |
| | 20 | 44 | | return app; |
| | | 45 | | } |
| | | 46 | | |
| | | 47 | | /// <summary>Registers each given middleware type on the pipeline, in order.</summary> |
| | | 48 | | /// <param name="middlewares">The middleware types to register. Each must derive from <see cref="WebApiMiddlewar |
| | | 49 | | /// <returns>The same <paramref name="app"/> instance, for chaining.</returns> |
| | | 50 | | /// <exception cref="ArgumentException">A type does not derive from <see cref="WebApiMiddleware"/>.</exception> |
| | | 51 | | public IApplicationBuilder UseWebApiMiddlewares(params IEnumerable<Type> middlewares) |
| | | 52 | | { |
| | 20 | 53 | | ArgumentNullException.ThrowIfNull(middlewares); |
| | | 54 | | |
| | 20 | 55 | | var types = middlewares.ToArray(); |
| | 22 | 56 | | var invalid = types.FirstOrDefault(middleware => !middleware.IsSubclassOf(typeof(WebApiMiddleware))); |
| | | 57 | | |
| | 20 | 58 | | if (invalid is not null) |
| | | 59 | | { |
| | 1 | 60 | | throw new ArgumentException( |
| | 1 | 61 | | $"{invalid.FullName} does not derive from {nameof(WebApiMiddleware)}.", nameof(middlewares)); |
| | | 62 | | } |
| | | 63 | | |
| | 40 | 64 | | foreach (var middleware in types) |
| | | 65 | | { |
| | 1 | 66 | | app.UseMiddleware(middleware); |
| | | 67 | | } |
| | | 68 | | |
| | 19 | 69 | | return app; |
| | | 70 | | } |
| | | 71 | | |
| | | 72 | | /// <summary>Serves the Swagger JSON endpoint and UI when the Swagger generator was registered, typically by |
| | | 73 | | /// <see cref="WebApplicationBuilderExtensions.AddWebApiSwagger"/> in an environment that allows it; otherwise d |
| | | 74 | | /// nothing, so the generator and the UI can never disagree.</summary> |
| | | 75 | | /// <returns>The same <paramref name="app"/> instance, for chaining.</returns> |
| | | 76 | | public IApplicationBuilder UseWebApiSwagger() |
| | | 77 | | { |
| | 20 | 78 | | var isService = app.ApplicationServices.GetService<IServiceProviderIsService>(); |
| | | 79 | | |
| | 20 | 80 | | if (isService?.IsService(typeof(ISwaggerProvider)) is not true) |
| | | 81 | | { |
| | 16 | 82 | | return app; |
| | | 83 | | } |
| | | 84 | | |
| | 4 | 85 | | app.UseSwagger(); |
| | 4 | 86 | | app.UseSwaggerUI(); |
| | | 87 | | |
| | 4 | 88 | | return app; |
| | | 89 | | } |
| | | 90 | | } |
| | | 91 | | } |