Search code examples
c#.netasp.net-coreswaggerlinqpad

Hosting a SwaggerUI-based service in LINQPad


I am writing an ASP.NET Core service based on .NET Framework 4.7.1. The service is meant to implement a REST API using Swagger and I need to (at least at first) be able to run it in LINQPad.

I have used NSwagStudio to generate a controller from the sample petstore yaml. However, I am struggling to figure out how to tie-in my controller with all of the ASP.NET Core glue code. I have found instructions online for doing this in .NET Core, but it appears that in .NET Framework things need to be done differently.

I would appreciate your help in connecting the dots. My sample code runs but navigating to the SwaggerUI gives me a message that "No operations defined in spec". I assume that this is happening because the controller is not being picked up, but I can't figure out what's missing!

References:

  <Reference>&lt;RuntimeDirectory&gt;\System.Net.Http.dll</Reference>
  <Reference>&lt;RuntimeDirectory&gt;\System.Runtime.Serialization.dll</Reference>
  <NuGetReference>Microsoft.AspNetCore</NuGetReference>
  <NuGetReference>Microsoft.AspNetCore.Hosting</NuGetReference>
  <NuGetReference>Microsoft.AspNetCore.Mvc</NuGetReference>
  <NuGetReference>Microsoft.AspNetCore.Mvc.WebApiCompatShim</NuGetReference>
  <NuGetReference>Microsoft.AspNetCore.StaticFiles</NuGetReference>
  <NuGetReference>Swashbuckle.AspNetCore</NuGetReference>
  <Namespace>Microsoft.AspNetCore</Namespace>
  <Namespace>Microsoft.AspNetCore.Builder</Namespace>
  <Namespace>Microsoft.AspNetCore.Hosting</Namespace>
  <Namespace>Microsoft.AspNetCore.Http</Namespace>
  <Namespace>Microsoft.Extensions.DependencyInjection</Namespace>
  <Namespace>Microsoft.OpenApi.Models</Namespace>
  <Namespace>System.Web.Http</Namespace>

Controller:

[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.9.4.0 (NJsonSchema v10.3.1.0 (Newtonsoft.Json v11.0.0.0))")]
[Microsoft.AspNetCore.Mvc.Route("petstore.swagger.io/v2")]
public partial class Controller : Microsoft.AspNetCore.Mvc.ApiController
{
    private IController _implementation;

    public Controller(IController implementation)
    {
        _implementation = implementation;
    }

    /// <summary>Add a new pet to the store</summary>
    /// <param name="accept_Language">The language you prefer for messages. Supported values are en-AU, en-CA, en-GB, en-US</param>
    /// <param name="cookieParam">Some cookie</param>
    [Microsoft.AspNetCore.Mvc.HttpPost, Microsoft.AspNetCore.Mvc.Route("pet")]
    public System.Threading.Tasks.Task AddPet([Microsoft.AspNetCore.Mvc.FromBody] object body, [Microsoft.AspNetCore.Mvc.FromHeader(Name = "Accept-Language")] string accept_Language, long cookieParam)
    {
        return _implementation.AddPetAsync(body, accept_Language ?? "en-AU", cookieParam);
    }

    /// ...
}

Main:

void Main()
{
    WebHost
        .CreateDefaultBuilder()
        .UseStartup<Startup>()
        .UseUrls("http://localhost:5000/")
        .Build()
        .Run();
}

Startup:

public class Startup
{
    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "Test API", Version = "v1" });
        });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.DocumentTitle = "Test Swagger Interface";
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "Test V1");
        });
    }
}

Solution

  • I am posting this in case someone else encounters the same problem. The issue was because of LINQPad; the same setup started working when I replicated it in Visual Studio!

    The only other thing you need to watch out for if you want to run this using .NET Framework is the version of the NuGet packages you refer to, as some of them are only compatible with .NET Core. I am including the (long list of) packages I ended up using, though it probably also includes a lot of things you won't actually need:

    <?xml version="1.0" encoding="utf-8"?>
    <packages>
      <package id="log4net" version="2.0.8" targetFramework="net471" />
      <package id="Microsoft.AspNet.WebApi.Client" version="5.2.6" targetFramework="net471" />
      <package id="Microsoft.AspNetCore" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Antiforgery" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Authentication.Abstractions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Authentication.Core" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Authorization" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Authorization.Policy" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Connections.Abstractions" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Cors" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Cryptography.Internal" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.DataProtection" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.DataProtection.Abstractions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Diagnostics" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Diagnostics.Abstractions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.HostFiltering" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Hosting" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Hosting.Abstractions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Hosting.Server.Abstractions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Html.Abstractions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Http" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Http.Abstractions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Http.Extensions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Http.Features" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.HttpOverrides" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.JsonPatch" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Localization" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Mvc" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Mvc.Abstractions" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Mvc.ApiExplorer" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Mvc.Core" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Mvc.Cors" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Mvc.DataAnnotations" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Mvc.Formatters.Json" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Mvc.Localization" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Mvc.Razor" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Mvc.Razor.Extensions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Mvc.RazorPages" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Mvc.TagHelpers" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Mvc.ViewFeatures" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Mvc.WebApiCompatShim" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Razor" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Razor.Design" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Razor.Language" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Razor.Runtime" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.ResponseCaching.Abstractions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Routing" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Routing.Abstractions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Server.IISIntegration" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Server.Kestrel" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Server.Kestrel.Core" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Server.Kestrel.Https" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets" version="2.1.3" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.StaticFiles" version="2.1.0" targetFramework="net471" />
      <package id="Microsoft.AspNetCore.WebUtilities" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Bcl.AsyncInterfaces" version="1.0.0" targetFramework="net471" />
      <package id="Microsoft.CodeAnalysis.Analyzers" version="1.1.0" targetFramework="net471" />
      <package id="Microsoft.CodeAnalysis.Common" version="2.8.0" targetFramework="net471" />
      <package id="Microsoft.CodeAnalysis.CSharp" version="2.8.0" targetFramework="net471" />
      <package id="Microsoft.CodeAnalysis.Razor" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.CSharp" version="4.5.0" targetFramework="net471" />
      <package id="Microsoft.DiaSymReader.Native" version="1.7.0" targetFramework="net471" />
      <package id="Microsoft.DotNet.PlatformAbstractions" version="2.1.0" targetFramework="net471" />
      <package id="Microsoft.Extensions.ApiDescription.Server" version="3.0.0" targetFramework="net471" developmentDependency="true" />
      <package id="Microsoft.Extensions.Caching.Abstractions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Caching.Memory" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Configuration" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Configuration.Abstractions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Configuration.Binder" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Configuration.CommandLine" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Configuration.EnvironmentVariables" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Configuration.FileExtensions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Configuration.Json" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Configuration.UserSecrets" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.DependencyInjection" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.DependencyModel" version="2.1.0" targetFramework="net471" />
      <package id="Microsoft.Extensions.FileProviders.Abstractions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.FileProviders.Composite" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.FileProviders.Embedded" version="2.1.0" targetFramework="net471" />
      <package id="Microsoft.Extensions.FileProviders.Physical" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.FileSystemGlobbing" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Hosting.Abstractions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Localization" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Localization.Abstractions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Logging" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Logging.Abstractions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Logging.Configuration" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Logging.Console" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Logging.Debug" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Logging.Log4Net.AspNetCore" version="2.2.6" targetFramework="net471" />
      <package id="Microsoft.Extensions.ObjectPool" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Options" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Options.ConfigurationExtensions" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.Primitives" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Extensions.WebEncoders" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.Net.Http.Headers" version="2.1.1" targetFramework="net471" />
      <package id="Microsoft.OpenApi" version="1.2.3" targetFramework="net471" />
      <package id="Microsoft.Win32.Registry" version="4.5.0" targetFramework="net471" />
      <package id="Newtonsoft.Json" version="11.0.2" targetFramework="net471" />
      <package id="Newtonsoft.Json.Bson" version="1.0.1" targetFramework="net471" />
      <package id="Swashbuckle.AspNetCore" version="5.6.3" targetFramework="net471" />
      <package id="Swashbuckle.AspNetCore.Swagger" version="5.6.3" targetFramework="net471" />
      <package id="Swashbuckle.AspNetCore.SwaggerGen" version="5.6.3" targetFramework="net471" />
      <package id="Swashbuckle.AspNetCore.SwaggerUI" version="5.6.3" targetFramework="net471" />
      <package id="System.AppContext" version="4.3.0" targetFramework="net471" />
      <package id="System.Buffers" version="4.5.0" targetFramework="net471" />
      <package id="System.Collections" version="4.3.0" targetFramework="net471" />
      <package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net471" />
      <package id="System.Collections.Immutable" version="1.5.0" targetFramework="net471" />
      <package id="System.ComponentModel.Annotations" version="4.5.0" targetFramework="net471" />
      <package id="System.Console" version="4.3.0" targetFramework="net471" />
      <package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net471" />
      <package id="System.Diagnostics.DiagnosticSource" version="4.5.1" targetFramework="net471" />
      <package id="System.Diagnostics.FileVersionInfo" version="4.3.0" targetFramework="net471" />
      <package id="System.Diagnostics.StackTrace" version="4.3.0" targetFramework="net471" />
      <package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net471" />
      <package id="System.Dynamic.Runtime" version="4.3.0" targetFramework="net471" />
      <package id="System.Globalization" version="4.3.0" targetFramework="net471" />
      <package id="System.IO" version="4.3.0" targetFramework="net471" />
      <package id="System.IO.Compression" version="4.3.0" targetFramework="net471" />
      <package id="System.IO.FileSystem" version="4.3.0" targetFramework="net471" />
      <package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net471" />
      <package id="System.IO.Pipelines" version="4.5.0" targetFramework="net471" />
      <package id="System.Linq" version="4.3.0" targetFramework="net471" />
      <package id="System.Linq.Expressions" version="4.3.0" targetFramework="net471" />
      <package id="System.Memory" version="4.5.3" targetFramework="net471" />
      <package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net471" />
      <package id="System.Reflection" version="4.3.0" targetFramework="net471" />
      <package id="System.Reflection.Metadata" version="1.6.0" targetFramework="net471" />
      <package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net471" />
      <package id="System.Runtime" version="4.3.0" targetFramework="net471" />
      <package id="System.Runtime.CompilerServices.Unsafe" version="4.6.0" targetFramework="net471" />
      <package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net471" />
      <package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net471" />
      <package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net471" />
      <package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net471" />
      <package id="System.Security.AccessControl" version="4.5.0" targetFramework="net471" />
      <package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net471" />
      <package id="System.Security.Cryptography.Cng" version="4.5.0" targetFramework="net471" />
      <package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net471" />
      <package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net471" />
      <package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net471" />
      <package id="System.Security.Cryptography.Xml" version="4.5.0" targetFramework="net471" />
      <package id="System.Security.Permissions" version="4.5.0" targetFramework="net471" />
      <package id="System.Security.Principal.Windows" version="4.5.0" targetFramework="net471" />
      <package id="System.Text.Encoding" version="4.3.0" targetFramework="net471" />
      <package id="System.Text.Encoding.CodePages" version="4.3.0" targetFramework="net471" />
      <package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net471" />
      <package id="System.Text.Encodings.Web" version="4.6.0" targetFramework="net471" />
      <package id="System.Text.Json" version="4.6.0" targetFramework="net471" />
      <package id="System.Threading" version="4.3.0" targetFramework="net471" />
      <package id="System.Threading.Tasks" version="4.3.0" targetFramework="net471" />
      <package id="System.Threading.Tasks.Extensions" version="4.5.3" targetFramework="net471" />
      <package id="System.Threading.Tasks.Parallel" version="4.3.0" targetFramework="net471" />
      <package id="System.Threading.Thread" version="4.3.0" targetFramework="net471" />
      <package id="System.ValueTuple" version="4.5.0" targetFramework="net471" />
      <package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net471" />
      <package id="System.Xml.XDocument" version="4.3.0" targetFramework="net471" />
      <package id="System.Xml.XmlDocument" version="4.3.0" targetFramework="net471" />
      <package id="System.Xml.XPath" version="4.3.0" targetFramework="net471" />
      <package id="System.Xml.XPath.XDocument" version="4.3.0" targetFramework="net471" />
    </packages>