因为项目需求,需要在Nancy
的基础上引入Swagger
,万能的互联网上有现成的方案, 方案写的很详细,实际按文档也成功的实现了相应的功能,但因为我是在基础dll里包含了该功能,所以我希望swagger-ui
是作为嵌入的资源,就跟Swashbuckle.AspNetCore
一样,使用的时候只要简单的声明相关代码,而且在最终的发布目录里面,也不需要包含swagger-ui
相关的目录。
参考Swashbuckle.AspNetCore
的相关代码SwaggerUIMiddleware,发现swagger-ui
的静态资源文件是通过StaticFileMiddleware
来实现的,这是一个很值得参考的思路。虽然Nancy
没有Middleware
,但它作为一个开源项目,肯定存在类似的功能实现。
首先我先下载了Nancy.Swagger
的源码以及它的官方帮助文档,期望从中找到它是否支持将swagger-ui
作为嵌入的资源,但很遗憾,它设计思路上就是不支持!
于是我只能通过各种可能的关键字(嵌入资源、Embedded Resource
等)在网上各种查找,终于找到了相关实现ResourceBootstrapper,原本我以为这是第三方实现,结果在Nancy
的源码中,我居然发现需要用到的EmbeddedStaticContentConventionBuilder
是已经存在了的!唯一有些差异的是,找到的例子代码是基于Nancy
1.x的,而我们项目中用的是Nancy
2.0,不过略微摸索过后,最终还是成功的接入了此部分!
最终相关代码部分如下,通过自定义NancyBootstrapper
类,注意ResourceViewLocationProvider.RootNamespaces.Add
方法用到的命名空间需要按实际调整
public class CustomBootstrapper : DefaultNancyBootstrapper
{
protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
{
base.ApplicationStartup(container, pipelines);
//设置Nancy Swagger相关信息
Nancy.Swagger.Services.SwaggerMetadataProvider.SetInfo("你的SwaggerTitle", "你的SwaggerVersion", "你的NancyHostSetting.SwaggerDesc");
//强制指定是当前类所在的Assembly
ResourceViewLocationProvider.RootNamespaces.Add(typeof(CustomBootstrapper).Assembly, "你嵌入的资源View所在的命名空间");
}
protected override Func<ITypeCatalog, NancyInternalConfiguration> InternalConfiguration
{
get
{
return NancyInternalConfiguration.WithOverrides(config =>
{
config.ViewLocationProvider = typeof(ResourceViewLocationProvider);
});
}
}
//protected override Func<ITypeCatalog, NancyInternalConfiguration> InternalConfiguration => category =>
//{
// var config = NancyInternalConfiguration.Default(category);
// config.ViewLocationProvider = typeof(ResourceViewLocationProvider);
// return config;
//};
protected override void ConfigureConventions(NancyConventions nancyConventions)
{
//设置静态资源路径
var resource = EmbeddedStaticContentConventionBuilder.AddDirectory("/swagger-ui", typeof(CustomBootstrapper).Assembly);
//typeof(CustomBootstrapper).Assembly 强制指定是当前类的Assembly
//不能用this.GetType().Assembly,如果有新的Bootstrapper继承自当前类,那么this.GetType().Assembly获取到的是子类的Assembly
nancyConventions.StaticContentsConventions.Add(resource);
base.ConfigureConventions(nancyConventions);
}
}
而嵌入的资源部分呢,则简单的配置如下
<ItemGroup>
<EmbeddedResource Include="swagger-ui/**/*" Exclude="swagger-ui/*.map;swagger-ui/*.json;swagger-ui/*.md" />
</ItemGroup>
有一点要注意的是,当存在多个INancyBootstrapper
,且存在多级继承时,会出现无法识别继承关系的问题报错Located multiple bootstrappers
,需要通过NancyBootstrapperLocator.Bootstrapper = new SomeCustomBootstrapper()
来指定。
补充下swagger-ui
的index
调整
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui/swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="./swagger-ui/index.css" />
<link rel="icon" type="image/png" href="./swagger-ui/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./swagger-ui/favicon-16x16.png" sizes="16x16" />
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui/swagger-ui-bundle.js" charset="UTF-8"></script>
<script src="./swagger-ui/swagger-ui-standalone-preset.js" charset="UTF-8"></script>
<script type="text/javascript">
window.onload = function () {
//<editor-fold desc="Changeable Configuration Block">
// the following lines will be replaced by docker/configurator, when it runs in a docker-container
window.ui = SwaggerUIBundle({
url: "@Model",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
});
//</editor-fold>
};
</script>
</body>
</html>
swagger-ui
在项目中的目录结构如下
其它资料
swagger-ui
的源码:https://github.com/swagger-api/swagger-ui