Skip to content

Support dynamic OpenApiConfigurationOptions #432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Aug 8, 2022
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using AutoFixture;

using Microsoft.Azure.Functions.Worker.Extensions.OpenApi.Extensions;
using Microsoft.Azure.Functions.Worker.Extensions.OpenApi.FunctionApp.OutOfProc.Configurations;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

Expand All @@ -13,7 +15,23 @@ public static void Main()
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults(worker => worker.UseNewtonsoftJson())
.ConfigureOpenApi()
.ConfigureServices(services => services.AddSingleton<Fixture>())
.ConfigureServices(services => {
services.AddSingleton<Fixture>();

// Example: If you want to change the configuration during startup of your function you can use the following code:

//services.AddSingleton<IOpenApiConfigurationOptions>(x =>
//{
// return new OpenApiConfigurationOptions()
// {
// Info = new Microsoft.OpenApi.Models.OpenApiInfo
// {
// Title = "A dynamic title generated at runtime",
// Description = "Dynamic Open API information at runtime"
// }
// };
//});
})
.Build();

host.Run();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
using AutoFixture;

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Resolvers;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.InProc.Configurations;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.InProc.Startup))]
Expand All @@ -12,7 +16,20 @@ public class Startup : FunctionsStartup
public override void Configure(IFunctionsHostBuilder builder)
{
var fixture = new Fixture();
builder.Services.AddSingleton(fixture);
builder.Services.AddSingleton(fixture);

// Example: If you want to change the configuration during startup of your function you can use the following code:

//var test = new OpenApiConfigurationOptions()
//{
// Info = new Microsoft.OpenApi.Models.OpenApiInfo
// {
// Title = "A dynamic title generated at runtime",
// Description = "Dynamic Open API information at runtime"
// }
//};

//OpenApiConfigurationResolver.ConfigurationOptions = test;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.Azure.Functions.Worker.Extensions.OpenApi.Functions;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Configurations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

Expand All @@ -20,7 +21,8 @@ public static IHostBuilder ConfigureOpenApi(this IHostBuilder hostBuilder)
hostBuilder.ConfigureServices(services =>
{
services.AddSingleton<IOpenApiHttpTriggerContext, OpenApiHttpTriggerContext>();
services.AddSingleton<IOpenApiTriggerFunction, OpenApiTriggerFunction>();
services.AddSingleton<IOpenApiTriggerFunction, OpenApiTriggerFunction>();
services.AddSingleton<IOpenApiConfigurationOptions, DefaultOpenApiConfigurationOptions>();
// services.AddSingleton<DefaultOpenApiHttpTrigger, DefaultOpenApiHttpTrigger>();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ public class OpenApiHttpTriggerContext : IOpenApiHttpTriggerContext
/// <summary>
/// Initializes a new instance of the <see cref="OpenApiHttpTriggerContext"/> class.
/// </summary>
public OpenApiHttpTriggerContext()
public OpenApiHttpTriggerContext(IOpenApiConfigurationOptions configOptions)
{
this._configOptions = configOptions;
this.PackageAssembly = this.GetAssembly<ISwaggerUI>();

var host = HostJsonResolver.Resolve();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,46 @@
using System;
using System.Linq;
using System.Reflection;

using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Configurations;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions;
using Microsoft.OpenApi.Models;
using System;
using System.Linq;
using System.Reflection;

namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Resolvers
{
/// <summary>
/// This represents the resolver entity for <see cref="OpenApiServer"/>.
/// </summary>
public static class OpenApiConfigurationResolver
{
{
/// <summary>
/// Property used to allow for dynamic generation of OpenApiConfigurationOptions
/// </summary>
public static IOpenApiConfigurationOptions ConfigurationOptions { get; set; }

/// <summary>
/// Gets the <see cref="IOpenApiConfigurationOptions"/> instance from the given assembly.
/// </summary>
/// <param name="assembly">The executing assembly instance.</param>
/// <returns>Returns the <see cref="IOpenApiConfigurationOptions"/> instance resolved.</returns>
public static IOpenApiConfigurationOptions Resolve(Assembly assembly)
{
{
// If we have already dynamically configured the <see cref="IOpenApiConfigurationOptions"/>, then return it
if (ConfigurationOptions != null)
{
return ConfigurationOptions;
}

var type = assembly.GetLoadableTypes()
.SingleOrDefault(p => p.GetInterface("IOpenApiConfigurationOptions", ignoreCase: true).IsNullOrDefault() == false
&& p.IsAbstract == false
&& p.GetCustomAttribute<ObsoleteAttribute>(inherit: false).IsNullOrDefault() == true);
if (type.IsNullOrDefault())
if (type.IsNullOrDefault())
{
var settings = new DefaultOpenApiConfigurationOptions();

return settings;
}
}

var options = Activator.CreateInstance(type);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class OpenApiHttpTriggerContext : IOpenApiHttpTriggerContext
private IOpenApiCustomUIOptions _uiOptions;

/// <summary>
/// Initializes a new instance of the <see cref="OpenApiTriggerFunctionProvider"/> class.
/// Initializes a new instance of the <see cref="OpenApiHttpTriggerContext"/> class.
/// </summary>
public OpenApiHttpTriggerContext()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class OpenApiHttpTriggerContextTests
public async Task Given_Type_When_Initiated_Then_It_Should_Return_ApplicationAssemblyWithGivenType(Type type)
{
var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var context = new OpenApiHttpTriggerContext();
var context = new OpenApiHttpTriggerContext(null);

var assembly = (await context.SetApplicationAssemblyAsync(location, false))
.ApplicationAssembly;
Expand All @@ -39,7 +39,7 @@ public async Task Given_Type_When_Initiated_Then_It_Should_Return_ApplicationAss
public async Task Given_Type_With_Referenced_Project_When_Initiated_Then_It_Should_Return_ApplicationAssemblyOfRootAssembly()
{
var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var context = new OpenApiHttpTriggerContext();
var context = new OpenApiHttpTriggerContext(null);

var assembly = (await context.SetApplicationAssemblyAsync(location, false))
.ApplicationAssembly;
Expand All @@ -55,7 +55,7 @@ public async Task Given_Type_With_Referenced_Project_When_Initiated_Then_It_Shou
public async Task Given_Type_When_Initiated_Then_It_Should_NotReturn_ApplicationAssemblyWithGivenType(Type type)
{
var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var context = new OpenApiHttpTriggerContext();
var context = new OpenApiHttpTriggerContext(null);

var assembly = (await context.SetApplicationAssemblyAsync(location, false))
.ApplicationAssembly;
Expand All @@ -69,7 +69,7 @@ public async Task Given_Type_When_Initiated_Then_It_Should_NotReturn_Application
public async Task Given_Type_When_Initiated_Then_It_Should_Return_PackageAssembly()
{
var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var context = new OpenApiHttpTriggerContext();
var context = new OpenApiHttpTriggerContext(null);

var assembly = (await context.SetApplicationAssemblyAsync(location, false))
.PackageAssembly;
Expand All @@ -81,7 +81,7 @@ public async Task Given_Type_When_Initiated_Then_It_Should_Return_PackageAssembl
public async Task Given_Type_When_Initiated_Then_It_Should_Return_OpenApiConfigurationOptions()
{
var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var context = new OpenApiHttpTriggerContext();
var context = new OpenApiHttpTriggerContext(null);

var options = (await context.SetApplicationAssemblyAsync(location, false))
.OpenApiConfigurationOptions;
Expand All @@ -94,7 +94,7 @@ public async Task Given_Type_When_Initiated_Then_It_Should_Return_OpenApiConfigu
public async Task Given_Type_When_Initiated_Then_It_Should_Return_OpenApiCustomUIOptions()
{
var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var context = new OpenApiHttpTriggerContext();
var context = new OpenApiHttpTriggerContext(null);

var options = (await context.SetApplicationAssemblyAsync(location, false))
.OpenApiCustomUIOptions;
Expand All @@ -107,7 +107,7 @@ public async Task Given_Type_When_Initiated_Then_It_Should_Return_OpenApiCustomU
public async Task Given_Type_When_Initiated_Then_It_Should_Return_HttpSettings()
{
var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var context = new OpenApiHttpTriggerContext();
var context = new OpenApiHttpTriggerContext(null);

var settings = (await context.SetApplicationAssemblyAsync(location, false))
.HttpSettings;
Expand All @@ -121,7 +121,7 @@ public async Task Given_Authorization_When_AuthorizeAsync_Invoked_Then_It_Should
{
var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var req = new Mock<IHttpRequestDataObject>();
var context = new OpenApiHttpTriggerContext();
var context = new OpenApiHttpTriggerContext(null);

var result = await context.SetApplicationAssemblyAsync(location, false)
.AuthorizeAsync(req.Object);
Expand All @@ -137,7 +137,7 @@ public async Task Given_Authorization_When_AuthorizeAsync_Invoked_Then_It_Should
public async Task Given_Type_When_GetOpenApiSpecVersion_Invoked_Then_It_Should_Return_Result(string version, OpenApiSpecVersion expected)
{
var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var context = new OpenApiHttpTriggerContext();
var context = new OpenApiHttpTriggerContext(null);

var result = (await context.SetApplicationAssemblyAsync(location, false))
.GetOpenApiSpecVersion(version);
Expand All @@ -151,7 +151,7 @@ public async Task Given_Type_When_GetOpenApiSpecVersion_Invoked_Then_It_Should_R
public async Task Given_Type_When_GetOpenApiSpecVersion_Invoked_Then_It_Should_Return_Result(string format, OpenApiFormat expected)
{
var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var context = new OpenApiHttpTriggerContext();
var context = new OpenApiHttpTriggerContext(null);

var result = (await context.SetApplicationAssemblyAsync(location, false))
.GetOpenApiFormat(format);
Expand Down