{"id":1291,"date":"2018-01-08T10:00:19","date_gmt":"2018-01-08T08:00:19","guid":{"rendered":"http:\/\/tpodolak.com\/blog\/?p=1291"},"modified":"2018-01-15T22:00:21","modified_gmt":"2018-01-15T20:00:21","slug":"asp-net-core-retrieving-swagger-specification-without-hosting-api","status":"publish","type":"post","link":"https:\/\/tpodolak.com\/blog\/2018\/01\/08\/asp-net-core-retrieving-swagger-specification-without-hosting-api\/","title":{"rendered":"ASP.NET Core &#8211; retrieving swagger specification without hosting API"},"content":{"rendered":"<h3>1. Introduction<\/h3>\n<p>I am currently exploring possible ways of removing a repetitive work when it comes to creating integration tests for our <i>API<\/i>. The one thing which usually takes some time when testing a new endpoint is a process of creating response and request classes (as we don&#8217;t share the models between API project and integration test project). That is why I would like to have some kind of a tool (<i>AutoRest<\/i> or <i>NSwag<\/i>) which would do it for us (possibly, in a prebuild step).  As those tools generate <i>API<\/i> clients based on swagger specification and I wanted this process to be as fast as possible I decided to figure out the way how to retrieve swagger specs without hosting the <i>API<\/i>.  <\/p>\n<h3>2. Implementation<\/h3>\n<p>After taking a look at <i>Swashbuckle.AspNetCore.Swagger<\/i> source code it turned out that <i>Swashbuckle.AspNetCore.Swagger.ISwaggerProvider<\/i> is responsible for creating a SwaggerDocument class. <i>JSON<\/i> representation of that class is a swagger specification. Having all of that in mind I wrote following piece of code.<\/p>\n<pre lang=\"csharp\">\r\npublic class SchemaRetriever\r\n{\r\n    private readonly Lazy<IWebHost> _webHostProxy = new Lazy<IWebHost>(() => Program.BuildWebHost(new string[0]));\r\n\r\n    private IWebHost WebHost => _webHostProxy.Value;\r\n        \r\n    public string RetrieveSchema(string swaggerDocument)\r\n    {\r\n        using (var scope = WebHost.Services.CreateScope())\r\n        {\r\n            var serviceProvider = scope.ServiceProvider;\r\n            var swaggerProvider = serviceProvider.GetRequiredService<ISwaggerProvider>();\r\n            var mvcJsonOptions = serviceProvider.GetRequiredService<IOptions<MvcJsonOptions>>();\r\n            var document = swaggerProvider.GetSwagger(swaggerDocument, null, \"\/\");\r\n\r\n            var serializer = new JsonSerializer\r\n                {\r\n                    NullValueHandling = NullValueHandling.Ignore,\r\n                    Formatting = mvcJsonOptions.Value.SerializerSettings.Formatting,\r\n                    ContractResolver = new SwaggerContractResolver(mvcJsonOptions.Value.SerializerSettings)\r\n                };\r\n\r\n            using (var stringWriter = new StringWriter())\r\n            {\r\n                serializer.Serialize(stringWriter, document);\r\n                return stringWriter.ToString();\r\n            }   \r\n        }\r\n    }\r\n}\r\n\r\npublic class Program\r\n{\r\n    public static void Main(string[] args)\r\n    {\r\n        BuildWebHost(args).Run();\r\n    }\r\n\r\n    public static IWebHost BuildWebHost(string[] args) =>\r\n            WebHost.CreateDefaultBuilder(args)\r\n                .UseStartup<Startup>()\r\n                .Build();\r\n}\r\n<\/pre>\n<p>The <i>Program<\/i> class is an entry point of the <i>API<\/i>. The only one difference compared to default <i>ASP.NET Core<\/i> template is the fact that I made the <i>BuildWebHost<\/i> method public. Thanks to that we can build the host (but without running) and get our hands on the <i>DI<\/i> container of our application. From that point the rest is easy, I retrieve the <i>ISwaggerProvider<\/i> from the container so I can get the swagger document for given id.<br \/>\n<a href=\"\/\/tpodolak.com\/blog\/wp-content\/uploads\/2018\/01\/asp-net-core-retrieving-swagger-specification-without-hosting-api\/TestWithoutHosting.png\"><img decoding=\"async\" src=\"\/\/tpodolak.com\/blog\/wp-content\/uploads\/2018\/01\/asp-net-core-retrieving-swagger-specification-without-hosting-api\/TestWithoutHosting.png\" alt=\"\" width=\"1066\" class=\"aligncenter size-full wp-image-1293\" srcset=\"https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2018\/01\/asp-net-core-retrieving-swagger-specification-without-hosting-api\/TestWithoutHosting.png 1066w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2018\/01\/asp-net-core-retrieving-swagger-specification-without-hosting-api\/TestWithoutHosting-150x22.png 150w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2018\/01\/asp-net-core-retrieving-swagger-specification-without-hosting-api\/TestWithoutHosting-300x44.png 300w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2018\/01\/asp-net-core-retrieving-swagger-specification-without-hosting-api\/TestWithoutHosting-1024x150.png 1024w\" sizes=\"(max-width: 1066px) 100vw, 1066px\" \/><\/a><br \/>\nIn order to make sure that the <i>SchemaRetriever<\/i> works as expected I wrote simple integration test which makes sure that swagger specs from hosted <i>API<\/i> is the same as the one retrieved without hosting.<\/p>\n<pre lang=\"csharp\">\r\n[Fact]\r\npublic async Task RetrieveSchema_RetrievesSwaggerSchema_SameAsDeployedSchema()\r\n{\r\n    var swaggerSchemaWithoutHosting = _subject.RetrieveSchema(_swaggerDocumentName);\r\n    using (var testServer = new TestServer(new WebHostBuilder().UseStartup<Startup>()))\r\n    {\r\n        using (var httpClient = testServer.CreateClient())\r\n        {\r\n            var response = await httpClient.GetAsync($\"swagger\/{EscapeDataString(_swaggerDocumentName)}\/swagger.json\");\r\n            response.EnsureSuccessStatusCode();\r\n            var content = await response.Content.ReadAsStringAsync();\r\n\r\n            swaggerSchemaWithoutHosting.Should().Be(content);\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p><a href=\"\/\/tpodolak.com\/blog\/wp-content\/uploads\/2018\/01\/asp-net-core-retrieving-swagger-specification-without-hosting-api\/IntegrationTest.png\"><img decoding=\"async\" src=\"\/\/tpodolak.com\/blog\/wp-content\/uploads\/2018\/01\/asp-net-core-retrieving-swagger-specification-without-hosting-api\/IntegrationTest.png\" alt=\"\" width=\"619\" class=\"aligncenter size-full wp-image-1292\" srcset=\"https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2018\/01\/asp-net-core-retrieving-swagger-specification-without-hosting-api\/IntegrationTest.png 619w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2018\/01\/asp-net-core-retrieving-swagger-specification-without-hosting-api\/IntegrationTest-150x49.png 150w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2018\/01\/asp-net-core-retrieving-swagger-specification-without-hosting-api\/IntegrationTest-300x98.png 300w\" sizes=\"(max-width: 619px) 100vw, 619px\" \/><\/a><br \/>\nSource code for this post can be found <a href=\"https:\/\/github.com\/tpodolak\/Blog\/tree\/master\/AspNetCoreManuallyRetrieveSwaggerSchema\">here<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>1. Introduction I am currently exploring possible ways of removing a repetitive work when it comes to creating integration tests for our API. The one thing which usually takes some time when testing a new endpoint is a process of creating response and request classes (as we don&#8217;t share the models between API project and [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[317],"tags":[318,331],"class_list":["post-1291","post","type-post","status-publish","format-standard","hentry","category-asp-net-core","tag-asp-net-core","tag-swagger"],"_links":{"self":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/1291","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/comments?post=1291"}],"version-history":[{"count":7,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/1291\/revisions"}],"predecessor-version":[{"id":1302,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/1291\/revisions\/1302"}],"wp:attachment":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/media?parent=1291"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/categories?post=1291"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/tags?post=1291"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}