Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions dotnet-client-libraries/SwashbuckleVsNSwag/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Swashbuckle vs. NSwag in ASP.NET Core

Sample for the Code Maze article [Swashbuckle vs. NSwag in ASP.NET Core](https://code-maze.com/aspnetcore-swashbuckle-vs-nswag/).

| Project | What it shows |
|---|---|
| `SwashbuckleVsNSwag.BuiltIn` | The built-in generator (`AddOpenApi()` and `MapOpenApi()`, JSON and YAML) with Swagger UI from `Swashbuckle.AspNetCore.SwaggerUi` |
| `SwashbuckleVsNSwag.Swashbuckle` | `AddSwaggerGen()`, `UseSwagger()` and `UseSwaggerUI()` |
| `SwashbuckleVsNSwag.NSwag` | `AddOpenApiDocument()`, `UseOpenApi()`, `UseSwaggerUi()` at `/swagger` and `UseReDoc()` at `/redoc` |
| `SwashbuckleVsNSwag.Benchmark` | BenchmarkDotNet GET and POST calls against the Swashbuckle and NSwag apps |

All three web apps serve their documentation in the Development environment only.

## Running the benchmark

The benchmark calls two running apps, so start both first, each in its own terminal, on their `https` profiles:

```
dotnet run --project SwashbuckleVsNSwag.Swashbuckle --launch-profile https # https://localhost:7060
dotnet run --project SwashbuckleVsNSwag.NSwag --launch-profile https # https://localhost:7089
```

Then run the benchmark in Release:

```
dotnet run -c Release --project SwashbuckleVsNSwag.Benchmark
```

If either app is not running, every benchmark reports `NA`.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ public class Program
static void Main(string[] args)
{
BenchmarkRunner.Run<SwashbuckleVsNSwagBenchmark>();
Console.ReadKey();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ public class RestClient
{
private static readonly HttpClient client = new HttpClient();

public async Task<Customer> GetCustomerAsync(string host)
public async Task<Customer?> GetCustomerAsync(string host)
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var id = "8e282cc4-71bd-4ffd-b63c-05e91ba79ad1";
return await client.GetFromJsonAsync<Customer>($"{host}/customer/{id}");
return await client.GetFromJsonAsync<Customer>($"{host}customer?customerId={id}");
}

public async Task PostCustomerAsync(string host)
Expand All @@ -34,7 +34,8 @@ public async Task PostCustomerAsync(string host)
}
};

await client.PostAsJsonAsync($"{host}/customer", customer);
var response = await client.PostAsJsonAsync($"{host}customer", customer);
response.EnsureSuccessStatusCode();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
<PackageReference Include="BenchmarkDotNet" Version="0.15.8" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public async Task NSwagGetResponse()
{
for (var i = 0; i < _size; i++)
{
_restClient.GetCustomerAsync("https://localhost:7089/");
await _restClient.GetCustomerAsync("https://localhost:7089/");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Mvc;
using SwashbuckleVsNSwag.Models.Customers;
using SwashbuckleVsNSwag.Repositories.CustomerRepository;

namespace SwashbuckleVsNSwag.BuiltIn.Controllers
{
[ApiController]
[Route("[controller]")]
public class CustomerController : ControllerBase
{
private readonly ILogger<CustomerController> _logger;
private readonly ICustomerRepository _customers;

public CustomerController(ILogger<CustomerController> logger, ICustomerRepository customers)
{
_logger = logger;
_customers = customers;
}

[HttpGet(Name = "GetCustomerById")]
public ActionResult<Customer> Get(Guid customerId)
{
return _customers.GetById(customerId);
}

[HttpPost(Name = "PostCustomer")]
public ActionResult<Customer> Post(Customer customer)
{
_customers.Add(customer);

return customer;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Mvc;
using SwashbuckleVsNSwag.Models.Orders;
using SwashbuckleVsNSwag.Repositories.OrderRepository;

namespace SwashbuckleVsNSwag.BuiltIn.Controllers
{
[ApiController]
[Route("[controller]")]
public class OrderController : ControllerBase
{
private readonly ILogger<OrderController> _logger;
private readonly IOrderRepository _orders;

public OrderController(ILogger<OrderController> logger, IOrderRepository orders)
{
_logger = logger;
_orders = orders;
}

[HttpGet(Name = "GetOrderById")]
public ActionResult<Order> Get(Guid orderId)
{
return _orders.GetById(orderId);
}

[HttpPost(Name = "PostOrder")]
public ActionResult<Order> Post(Order order)
{
_orders.Add(order);

return order;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Mvc;
using SwashbuckleVsNSwag.Models.Products;
using SwashbuckleVsNSwag.Repositories.ProductRepository;

namespace SwashbuckleVsNSwag.BuiltIn.Controllers
{
[ApiController]
[Route("[controller]")]
public class ProductController : ControllerBase
{
private readonly ILogger<ProductController> _logger;
private readonly IProductRepository _products;

public ProductController(ILogger<ProductController> logger, IProductRepository products)
{
_logger = logger;
_products = products;
}

[HttpGet(Name = "GetProductById")]
public ActionResult<Product> Get(Guid productId)
{
return _products.GetById(productId);
}

[HttpPost(Name = "PostProduc")]
public ActionResult<Product> Post(Product product)
{
_products.Add(product);

return product;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using SwashbuckleVsNSwag.Repositories.CustomerRepository;
using SwashbuckleVsNSwag.Repositories.OrderRepository;
using SwashbuckleVsNSwag.Repositories.ProductRepository;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();

//Built-in OpenAPI document generation (Microsoft.AspNetCore.OpenApi)
builder.Services.AddOpenApi();

builder.Services.AddSingleton<ICustomerRepository, CustomerRepository>();
builder.Services.AddSingleton<IProductRepository, ProductRepository>();
builder.Services.AddSingleton<IOrderRepository, OrderRepository>();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
//Serve the document as JSON and as YAML
app.MapOpenApi();
app.MapOpenApi("/openapi/{documentName}.yaml");

//Swagger UI from Swashbuckle.AspNetCore.SwaggerUi, pointed at the built-in document
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/openapi/v1.json", "API using built-in OpenAPI");
});
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
{
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:7341",
"sslPort": 44381
"applicationUrl": "http://localhost:40377",
"sslPort": 44377
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "weatherforecast",
"applicationUrl": "http://localhost:5191",
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5108",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
Expand All @@ -23,16 +23,16 @@
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "weatherforecast",
"applicationUrl": "https://localhost:7117;http://localhost:5191",
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7071;http://localhost:5108",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.12" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUi" Version="10.3.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\SwashbuckleVsNSwag.Models\SwashbuckleVsNSwag.Models.csproj" />
<ProjectReference Include="..\SwashbuckleVsNSwag.Repositories\SwashbuckleVsNSwag.Repositories.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace SwashbuckleVsNSwag.NSwag.Tests
{
public class CustomerConsollerTest
public class CustomerControllerTest
{
private Mock<ILogger<CustomerController>> _logger;
private Mock<ICustomerRepository> _customerRepository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace SwashbuckleVsNSwag.NSwag.Tests
{
public class OrderConsollerTest
public class OrderControllerTest
{
private Mock<ILogger<OrderController>> _logger;
private Mock<IOrderRepository> _orderRepository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace SwashbuckleVsNSwag.NSwag.Tests
{
public class ProductConsollerTest
public class ProductControllerTest
{
private Mock<ILogger<ProductController>> _logger;
private Mock<IProductRepository> _productRepository;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.10.1" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NUnit.Analyzers" Version="3.3.0" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
<PackageReference Include="NUnit" Version="5.0.0" />
<PackageReference Include="NUnit3TestAdapter" Version="6.3.1" />
<PackageReference Include="NUnit.Analyzers" Version="4.15.0" />
<PackageReference Include="coverlet.collector" Version="10.1.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
builder.Services.AddControllers();

//NSwag configuration
builder.Services.AddOpenApiDocument(c =>
{
c.DocumentName = "v1";
c.Title = "API using NSwag";
c.Version = "v1";
builder.Services.AddOpenApiDocument(c =>
{
c.DocumentName = "v1";
c.Title = "API using NSwag";
c.Version = "v1";
});

builder.Services.AddSingleton<ICustomerRepository, CustomerRepository>();
Expand All @@ -26,8 +26,13 @@
if (app.Environment.IsDevelopment())
{
//Enable Swagger
app.UseOpenApi(p => p.Path = "/swagger/v1/swagger.yaml");
app.UseReDoc(p => p.DocumentPath = "/swagger/v1/swagger.yaml");
app.UseOpenApi(p => p.Path = "/swagger/v1/swagger.yaml");
app.UseSwaggerUi(p => p.DocumentPath = "/swagger/v1/swagger.yaml");
app.UseReDoc(p =>
{
p.Path = "/redoc";
p.DocumentPath = "/swagger/v1/swagger.yaml";
});
}

app.UseHttpsRedirection();
Expand Down
Loading
Loading