To change the head content of the Swagger page, we can write
applicationBuilder.UseSwaggerUI(options =>
options.HeadContent = ...
);
However, this is called only once during startup and thus stays static. Is it possible to add dynamic additional content to the Swagger page or dynamically change the head content at a later stage? (Simple toy example: show the current time or the value of a counter.)
You can see this line in SwaggerUIOptions
:
/// <summary>
/// Gets or sets additional content to place in the head of the swagger-ui page
/// </summary>
public string HeadContent { get; set; } = "";
HeadContent
is actually a string type and is received by %(HeadContent)
on the default index page of Swagger
. So if you pass a value through HeadContent
, it seems like it can only be rendered as static content.
You can customize Swagger's index.html and replace %(HeadContent)
in it, and then render it dynamically through JavaScript.
app.UseSwaggerUI(config =>
{
//I add index.html in the root directory, please pay attention to your path
config.IndexStream = () => Assembly.GetExecutingAssembly()
.GetManifestResourceStream("YourProjectName.index.html");
}
Set index.html as Embedded resource
:
<ItemGroup>
<EmbeddedResource Include="index.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
To get started, you should base your custom index.html on the default version.
Take displaying the current time as an example, below is my index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>%(DocumentTitle)</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css">
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
background: #fafafa;
}
#wrapper {
font-size: 50px;
font-weight: bold;
}
</style>
//Replace %(HeadContent) here
<div id="wrapper"></div>
<!--%(HeadContent)-->
</head>
<body>
<div id="swagger-ui"></div>
</body>
<script>
if (window.navigator.userAgent.indexOf("Edge") > -1) {
console.log("Removing native Edge fetch in favor of swagger-ui's polyfill")
window.fetch = undefined;
}
</script>
<script src="./swagger-ui-bundle.js"></script>
<script src="./swagger-ui-standalone-preset.js"></script>
<script>
/* Source: https://gist.github.com/lamberta/3768814
* Parse a string function definition and return a function object. Does not use eval.
* @param {string} str
* @return {function}
*
* Example:
* var f = function (x, y) { return x * y; };
* var g = parseFunction(f.toString());
* g(33, 3); //=> 99
*/
//Here is my JavaScript code:
function test(){
var date=new Date();
var year = date.getFullYear();
var month = date.getMonth()+1;
var day = date.getDate();
var hour = date.getHours();
var minute = date.getMinutes();
var second = date.getSeconds();
if(month<10){
month = "0"+month;
}
if(day<10){
day = "0"+day;
}
if(hour<10){
hour = "0"+hour;
}
if(minute<10){
minute = "0"+minute;
}
if(second<10){
second = "0"+second;
}
document.getElementById("wrapper").innerHTML = `${year}-${month}-${day} ${hour}:${minute}:${second}`;
}
setInterval("test()",1000);
function parseFunction(str) {
if (!str) return void (0);
var fn_body_idx = str.indexOf('{'),
fn_body = str.substring(fn_body_idx + 1, str.lastIndexOf('}')),
fn_declare = str.substring(0, fn_body_idx),
fn_params = fn_declare.substring(fn_declare.indexOf('(') + 1, fn_declare.lastIndexOf(')')),
args = fn_params.split(',');
args.push(fn_body);
function Fn() {
return Function.apply(this, args);
}
Fn.prototype = Function.prototype;
return new Fn();
}
window.onload = function () {
var configObject = JSON.parse('%(ConfigObject)');
var oauthConfigObject = JSON.parse('%(OAuthConfigObject)');
// Workaround for https://github.com/swagger-api/swagger-ui/issues/5945
configObject.urls.forEach(function (item) {
if (item.url.startsWith("http") || item.url.startsWith("/")) return;
item.url = window.location.href.replace("index.html", item.url).split('#')[0];
});
// If validatorUrl is not explicitly provided, disable the feature by setting to null
if (!configObject.hasOwnProperty("validatorUrl"))
configObject.validatorUrl = null
// If oauth2RedirectUrl isn't specified, use the built-in default
if (!configObject.hasOwnProperty("oauth2RedirectUrl"))
configObject.oauth2RedirectUrl = (new URL("oauth2-redirect.html", window.location.href)).href;
// Apply mandatory parameters
configObject.dom_id = "#swagger-ui";
configObject.presets = [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset];
configObject.layout = "StandaloneLayout";
// Parse and add interceptor functions
var interceptors = JSON.parse('%(Interceptors)');
if (interceptors.RequestInterceptorFunction)
configObject.requestInterceptor = parseFunction(interceptors.RequestInterceptorFunction);
if (interceptors.ResponseInterceptorFunction)
configObject.responseInterceptor = parseFunction(interceptors.ResponseInterceptorFunction);
// Begin Swagger UI call region
const ui = SwaggerUIBundle(configObject);
ui.initOAuth(oauthConfigObject);
// End Swagger UI call region
window.ui = ui
}
</script>
</body>
</html>
Test Result: