Provide extensibility for UI customizations (#74)
This commit is contained in:
Родитель
93423b6217
Коммит
ee89ea3461
|
@ -0,0 +1,18 @@
|
|||
using System.Reflection;
|
||||
|
||||
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Configurations;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static.Configurations
|
||||
{
|
||||
public class OpenApiCustomUIOptions : DefaultOpenApiCustomUIOptions
|
||||
{
|
||||
public OpenApiCustomUIOptions(Assembly assembly)
|
||||
: base(assembly)
|
||||
{
|
||||
}
|
||||
|
||||
public override string CustomStylesheetPath { get; } = "dist.my-custom.css";
|
||||
|
||||
public override string CustomJavaScriptPath { get; } = "dist.my-custom.js";
|
||||
}
|
||||
}
|
|
@ -40,6 +40,13 @@
|
|||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Uncomment this block if you want to use custom UI -->
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="dist\my-custom.css" />
|
||||
<EmbeddedResource Include="dist\my-custom.js" />
|
||||
</ItemGroup>
|
||||
<!-- Uncomment this block if you want to use custom UI -->
|
||||
|
||||
<!-- Comment this block if you want to use NuGet package from https://nuget.org -->
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\templates\OpenApiEndpoints\IOpenApiHttpTriggerContext.cs" />
|
||||
|
|
3
samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static/dist/my-custom.css
поставляемый
Normal file
3
samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static/dist/my-custom.css
поставляемый
Normal file
|
@ -0,0 +1,3 @@
|
|||
.swagger-ui .topbar {
|
||||
background-color: #003399
|
||||
}
|
1
samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static/dist/my-custom.js
поставляемый
Normal file
1
samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static/dist/my-custom.js
поставляемый
Normal file
|
@ -0,0 +1 @@
|
|||
console.log("Custom UI: Open API Sample on Azure Functions (STATIC)");
|
|
@ -0,0 +1,67 @@
|
|||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
|
||||
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Configurations
|
||||
{
|
||||
/// <summary>
|
||||
/// Default implementation of <see cref="IOpenApiCustomUIOptions"/>, providing
|
||||
/// empty replacements for custom javascript and stylesheets
|
||||
/// </summary>
|
||||
public class DefaultOpenApiCustomUIOptions : IOpenApiCustomUIOptions
|
||||
{
|
||||
private readonly Assembly _assembly;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DefaultOpenApiCustomUIOptions"/> class.
|
||||
/// </summary>
|
||||
/// <param name="assembly"><see cref="Assembly"/> instance.</param>
|
||||
public DefaultOpenApiCustomUIOptions(Assembly assembly)
|
||||
{
|
||||
this._assembly = assembly.ThrowIfNullOrDefault();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual string CustomStylesheetPath { get; } = "dist.custom.css";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual string CustomJavaScriptPath { get; } = "dist.custom.js";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<string> GetStylesheetAsync()
|
||||
{
|
||||
using (var stream = this._assembly.GetManifestResourceStream($"{this._assembly.GetName().Name}.{this.CustomStylesheetPath}"))
|
||||
{
|
||||
if (stream.IsNullOrDefault())
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
return await reader.ReadToEndAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<string> GetJavaScriptAsync()
|
||||
{
|
||||
using (var stream = this._assembly.GetManifestResourceStream($"{this._assembly.GetName().Name}.{this.CustomJavaScriptPath}"))
|
||||
{
|
||||
if (stream.IsNullOrDefault())
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
return await reader.ReadToEndAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for a custom UI provider that can provide custom javascript
|
||||
/// and CSS to be populated on a page
|
||||
/// </summary>
|
||||
public interface IOpenApiCustomUIOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the filepath for stylesheet for custom UI.
|
||||
/// </summary>
|
||||
string CustomStylesheetPath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets filepath for JavaScript for custom UI.
|
||||
/// </summary>
|
||||
string CustomJavaScriptPath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the stylesheet to be rendered on the page.
|
||||
/// </summary>
|
||||
/// <returns>The stylesheet string for custom UI.</returns>
|
||||
Task<string> GetStylesheetAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the javascript to be rendered on the page.
|
||||
/// </summary>
|
||||
/// <returns>The JavaScript string for custom UI.</returns>
|
||||
Task<string> GetJavaScriptAsync();
|
||||
}
|
||||
}
|
|
@ -30,8 +30,9 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions
|
|||
/// <summary>
|
||||
/// Builds Swagger UI document.
|
||||
/// </summary>
|
||||
/// <param name="options"><see cref="IOpenApiCustomUIOptions"/> instance.</param>
|
||||
/// <returns><see cref="ISwaggerUI"/> instance.</returns>
|
||||
Task<ISwaggerUI> BuildAsync();
|
||||
Task<ISwaggerUI> BuildAsync(IOpenApiCustomUIOptions options = null);
|
||||
|
||||
/// <summary>
|
||||
/// Builds OAuth2 Redirect document.
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
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;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Resolvers
|
||||
{
|
||||
/// <summary>
|
||||
/// This represents the resolver entity for <see cref="IOpenApiCustomUIOptions"/>.
|
||||
/// </summary>
|
||||
public static class OpenApiCustomUIResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IOpenApiCustomUIOptions"/> instance from the given assembly.
|
||||
/// </summary>
|
||||
/// <param name="assembly">The executing assembly instance.</param>
|
||||
/// <returns>Returns the <see cref="IOpenApiCustomUIOptions"/> instance resolved.</returns>
|
||||
public static IOpenApiCustomUIOptions Resolve(Assembly assembly)
|
||||
{
|
||||
var type = assembly.GetTypes()
|
||||
.SingleOrDefault(p => p.GetInterface("IOpenApiCustomUIOptions", ignoreCase: true).IsNullOrDefault() == false);
|
||||
if (type.IsNullOrDefault())
|
||||
{
|
||||
return new DefaultOpenApiCustomUIOptions(assembly);
|
||||
}
|
||||
|
||||
var options = Activator.CreateInstance(type, assembly);
|
||||
|
||||
return options as IOpenApiCustomUIOptions;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,9 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core
|
|||
{
|
||||
private const string SwaggerUITitlePlaceholder = "[[SWAGGER_UI_TITLE]]";
|
||||
private const string SwaggerUICssPlaceholder = "[[SWAGGER_UI_CSS]]";
|
||||
private const string SwaggerUICustomCssPlaceholder = "[[SWAGGER_UI_CUSTOM_CSS]]";
|
||||
private const string SwaggerUIBundleJsPlaceholder = "[[SWAGGER_UI_BUNDLE_JS]]";
|
||||
private const string SwaggerUICustomJsPlaceholder = "[[SWAGGER_UI_CUSTOM_JS]]";
|
||||
private const string SwaggerUIStandalonePresetJsPlaceholder = "[[SWAGGER_UI_STANDALONE_PRESET_JS]]";
|
||||
private const string SwaggerUIApiPrefix = "[[SWAGGER_UI_API_PREFIX]]";
|
||||
private const string SwaggerUrlPlaceholder = "[[SWAGGER_URL]]";
|
||||
|
@ -32,7 +34,9 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core
|
|||
private OpenApiInfo _info;
|
||||
private string _baseUrl;
|
||||
private string _swaggerUiCss;
|
||||
private string _swaggerUiCustomCss;
|
||||
private string _swaggerUiBundleJs;
|
||||
private string _swaggerUiCustomJs;
|
||||
private string _swaggerUiStandalonePresetJs;
|
||||
private string _swaggerUiApiPrefix;
|
||||
private string _indexHtml;
|
||||
|
@ -73,10 +77,16 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ISwaggerUI> BuildAsync()
|
||||
public async Task<ISwaggerUI> BuildAsync(IOpenApiCustomUIOptions options = null)
|
||||
{
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
|
||||
if (!options.IsNullOrDefault())
|
||||
{
|
||||
this._swaggerUiCustomCss = await options.GetStylesheetAsync();
|
||||
this._swaggerUiCustomJs = await options.GetJavaScriptAsync();
|
||||
}
|
||||
|
||||
using (var stream = assembly.GetManifestResourceStream(swaggerUiCss))
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
|
@ -152,7 +162,9 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core
|
|||
|
||||
var html = this._indexHtml.Replace(SwaggerUITitlePlaceholder, swaggerUiTitle)
|
||||
.Replace(SwaggerUICssPlaceholder, this._swaggerUiCss)
|
||||
.Replace(SwaggerUICustomCssPlaceholder, this._swaggerUiCustomCss)
|
||||
.Replace(SwaggerUIBundleJsPlaceholder, this._swaggerUiBundleJs)
|
||||
.Replace(SwaggerUICustomJsPlaceholder, this._swaggerUiCustomJs)
|
||||
.Replace(SwaggerUIStandalonePresetJsPlaceholder, this._swaggerUiStandalonePresetJs)
|
||||
.Replace(SwaggerUrlPlaceholder, swaggerUrl);
|
||||
|
||||
|
|
|
@ -28,12 +28,14 @@
|
|||
margin:0;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
[[SWAGGER_UI_CUSTOM_CSS]]
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
|
||||
<script>[[SWAGGER_UI_CUSTOM_JS]]</script>
|
||||
<script>[[SWAGGER_UI_BUNDLE_JS]]</script>
|
||||
<script>[[SWAGGER_UI_STANDALONE_PRESET_JS]]</script>
|
||||
<script>
|
||||
|
|
|
@ -23,6 +23,11 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
|
|||
/// </summary>
|
||||
IOpenApiConfigurationOptions OpenApiConfiguration { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IOpenApiCustomUIOptions"/> instance.
|
||||
/// </summary>
|
||||
IOpenApiCustomUIOptions OpenApiCustomUIOptions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="HttpSettings"/> instance.
|
||||
/// </summary>
|
||||
|
|
|
@ -121,7 +121,7 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
|
|||
var result = await context.SwaggerUI
|
||||
.AddMetadata(context.OpenApiConfiguration.Info)
|
||||
.AddServer(req, context.HttpSettings.RoutePrefix, context.OpenApiConfiguration)
|
||||
.BuildAsync()
|
||||
.BuildAsync(context.OpenApiCustomUIOptions)
|
||||
.RenderAsync("swagger.json", context.GetSwaggerAuthKey())
|
||||
.ConfigureAwait(false);
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
|
|||
var host = HostJsonResolver.Resolve();
|
||||
|
||||
this.OpenApiConfiguration = OpenApiConfigurationResolver.Resolve(this.GetExecutingAssembly());
|
||||
this.OpenApiCustomUIOptions = OpenApiCustomUIResolver.Resolve(this.GetExecutingAssembly());
|
||||
this.HttpSettings = host.GetHttpSettings();
|
||||
|
||||
var filter = new RouteConstraintFilter();
|
||||
|
@ -50,6 +51,9 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi
|
|||
/// <inheritdoc />
|
||||
public virtual IOpenApiConfigurationOptions OpenApiConfiguration { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual IOpenApiCustomUIOptions OpenApiCustomUIOptions { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual HttpSettings HttpSettings { get; }
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче