/// <summary> /// Creates an instance of the <see cref="OpenApiOperationInvoker{TRequest, TResponse}"/>. /// </summary> /// <param name="operationLocator">The operation locator.</param> /// <param name="parameterBuilder">The parameter builder.</param> /// <param name="accessChecker">The access checker.</param> /// <param name="exceptionMapper">The exception mapper.</param> /// <param name="resultBuilder">The result builder.</param> /// <param name="configuration">The <see cref="IOpenApiConfiguration"/>.</param> /// <param name="auditContext">The audit context.</param> /// <param name="logger">The logger.</param> /// <param name="operationsInstrumentation">Operations instrumentation.</param> /// <param name="exceptionsInstrumentation">Exceptions instrumentation.</param> public OpenApiOperationInvoker( IOpenApiServiceOperationLocator operationLocator, IOpenApiParameterBuilder <TRequest> parameterBuilder, IOpenApiAccessChecker accessChecker, IOpenApiExceptionMapper exceptionMapper, IOpenApiResultBuilder <TResponse> resultBuilder, IOpenApiConfiguration configuration, IAuditContext auditContext, ILogger <OpenApiOperationInvoker <TRequest, TResponse> > logger, IOperationsInstrumentation <OpenApiOperationInvoker <TRequest, TResponse> > operationsInstrumentation, IExceptionsInstrumentation <OpenApiOperationInvoker <TRequest, TResponse> > exceptionsInstrumentation) { this.operationLocator = operationLocator; this.parameterBuilder = parameterBuilder; this.accessChecker = accessChecker; this.exceptionMapper = exceptionMapper; this.resultBuilder = resultBuilder; this.auditContext = auditContext; this.logger = logger; this.operationsInstrumentation = operationsInstrumentation; this.configuration = configuration; this.exceptionsInstrumentation = exceptionsInstrumentation; }
/// <summary> /// Configure Open API hosting using an <see cref="IOpenApiHost"/>. /// </summary> /// <typeparam name="TRequest">The type of the request.</typeparam> /// <typeparam name="TResponse">The type of the response.</typeparam> /// <param name="services">The services collection to configure.</param> /// <param name="configureHost">A function used to configure the host.</param> /// <param name="configureEnvironment">A function used to optionally configure the hosting environment.</param> /// <returns>The configured <see cref="IServiceCollection"/>.</returns> /// <remarks> /// <para> /// See <see cref="IOpenApiService"/> for details on using the Open API hosting environment. /// </para> /// <para> /// To host in functions, you should provide a function entry point with a catch-all for your base URI, and any operation types you need to support (GET, POST etc.) /// </para> /// <para> /// <code> /// [FunctionName("openapihostroot")] /// public static Task<IActionResult> RunAsync([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "{*path}")]HttpRequest req, ExecutionContext context, ILogger log) /// { /// Initialize(context); /// /// var host = ServiceRoot.ServiceProvider.GetRequiredService<OpenApiHttpRequestHost>(); /// return host.HandleRequest(req); /// } /// </code> /// </para> /// <para> /// Initialization is handled using this method, during Functions container initialization. /// </para> /// <para> /// <code> /// private static void Initialize(ExecutionContext context) /// { /// Functions.InitializeContainer(context, services => /// { /// services.AddOpenApiHttpHosting(host => /// { /// using (var stream = File.OpenRead(".\\yaml\\petstore.yaml")) /// { /// var openApiDocument = new OpenApiStreamReader().Read(stream, out var diagnostics); /// host.AddDocument(openApiDocument); /// } /// }); /// /// // We can add all the services here /// services.AddSingleton<IOpenApiService, PetStoreService>(); /// }); /// } /// </code> /// </para> /// <para> /// You can add as many <see cref="IOpenApiService"/> instances to the container as you have, but the framework will /// <i>only</i> expose those that are bound to Open API documents that you have added to the host. While you typically /// add documents on startup, you can add more at runtime to light up services that are registered in the container, but not /// actually bound to Open API documents. /// </para> /// <para> /// See <see cref="IOpenApiService"/> for more details on configuring the host using this mechanism. /// </para> /// </remarks> public static IServiceCollection AddOpenApiHosting <TRequest, TResponse>( this IServiceCollection services, Action <OpenApiHostConfiguration>?configureHost, Action <IOpenApiConfiguration>?configureEnvironment = null) { if (services.Any(s => typeof(IOpenApiHost <TRequest, TResponse>).IsAssignableFrom(s.ServiceType))) { return(services); } services.AddJsonSerializerSettings(); services.AddInstrumentation(); services.AddOpenApiAuditing(); services.AddAuditLogSink <ConsoleAuditLogSink>(); services.AddSingleton <JsonConverter, OpenApiDocumentJsonConverter>(); services.AddSingleton <JsonConverter, HalDocumentJsonConverter>(); services.AddSingleton <IOpenApiDocumentProvider, OpenApiDocumentProvider>(); services.AddSingleton <IHalDocumentFactory, HalDocumentFactory>(); services.AddTransient <HalDocument>(); services.AddSingleton <IOpenApiServiceOperationLocator, DefaultOperationLocator>(); services.AddSingleton <IPathMatcher, PathMatcher>(); services.AddSingleton <IOpenApiService, SwaggerService>(); services.AddSingleton <IOpenApiLinkOperationMapper, OpenApiLinkOperationMapper>(); services.AddSingleton <IOpenApiAccessChecker, OpenApiAccessChecker>(); services.AddSingleton <IOpenApiExceptionMapper, OpenApiExceptionMapper>(); services.AddSingleton <IOpenApiWebLinkResolver, OpenApiWebLinkResolver>(); services.AddSingleton <IAuditContext, AuditContext>(); services.AddSingleton <IOpenApiOperationInvoker <TRequest, TResponse>, OpenApiOperationInvoker <TRequest, TResponse> >(); services.AddSingleton((Func <IServiceProvider, IOpenApiHost <TRequest, TResponse> >)(serviceProvider => { var result = new OpenApiHost <TRequest, TResponse>( serviceProvider.GetRequiredService <IPathMatcher>(), serviceProvider.GetRequiredService <IOpenApiContextBuilder <TRequest> >(), serviceProvider.GetRequiredService <IOpenApiOperationInvoker <TRequest, TResponse> >(), serviceProvider.GetRequiredService <IOpenApiResultBuilder <TResponse> >()); IOpenApiExceptionMapper exceptionMapper = serviceProvider.GetRequiredService <IOpenApiExceptionMapper>(); exceptionMapper.Map <OpenApiBadRequestException>(400); exceptionMapper.Map <OpenApiUnauthorizedException>(401); exceptionMapper.Map <OpenApiForbiddenException>(403); exceptionMapper.Map <OpenApiNotFoundException>(404); var hostConfiguration = new OpenApiHostConfiguration(serviceProvider.GetRequiredService <IOpenApiDocumentProvider>(), exceptionMapper, serviceProvider.GetRequiredService <IOpenApiLinkOperationMapper>()); serviceProvider.GetServices <IHalDocumentMapper>().ForEach(mapper => mapper.ConfigureLinkMap(hostConfiguration.Links)); configureHost?.Invoke(hostConfiguration); return(result); })); services.AddSingleton <IOpenApiConfiguration>(serviceProvider => { var config = new OpenApiConfiguration(serviceProvider); configureEnvironment?.Invoke(config); return(config); }); services.AddOpenApiJsonConverters(); services.AddOpenApiExceptionMappers(); return(services); }