Since latest 2-3 releases (I don't know exactly which one) I notice that the default content-type selected on the swagger HTML dropdown menu for the method reponse, is not "application/json" but "text/plain".
If I don't change it everytime before clicking on Try button, I get an error because no content-type negotiation for responses is allowed in my application.
I think that "application/json" should be the right default value, but anyway is it possible to set the default content-type for response in Swagger configuration to avoid changing it everytime?
This is my actual configuration
```c#
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(config =>
{
// HTTP 406 when not supported format is requested by client
config.ReturnHttpNotAcceptable = true;
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
// Add FluentValidation
.AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining
// Add API versioning
services.AddApiVersioning(options =>
{
options.AssumeDefaultVersionWhenUnspecified = true;
options.DefaultApiVersion = new ApiVersion(1, 0);
options.ReportApiVersions = true;
});
}
```
The HTML result

I just tried with the latest version (v18.19.0) and it is set to json by default (it only has json):

Can you provide a sample and/or provide the controller code?
Can you also show your NSwag middleware registration in startup.cs?
@RSuter
I've already updated to v11.19.0.
Here it is my Startup.cs
```c#
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(config =>
{
// HTTP 406 when not supported format is requested by client
config.ReturnHttpNotAcceptable = true;
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
// Add FluentValidation
.AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<MachineCreateModelValidator>());
// Add API versioning
services.AddApiVersioning(options =>
{
options.AssumeDefaultVersionWhenUnspecified = true;
options.DefaultApiVersion = new ApiVersion(1, 0);
options.ReportApiVersions = true;
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseHsts();
// Add Exception handling
app.UseGlobalExceptionHandler();
}
// Add Swagger
app.UseSwagger();
app.UseMvc();
}
}
`UseSwagger` extension method
```c#
public static class ServiceExtensions
{
public static void UseSwagger(this IApplicationBuilder app)
{
string title = "My Control API";
string description = "My API for Core functionalities.";
app.UseSwaggerWithApiExplorer(config =>
{
config.GeneratorSettings.OperationProcessors.TryGet<ApiVersionProcessor>().IncludedVersions = new[] { "1.0" };
config.SwaggerRoute = "v1.0.json";
config.GeneratorSettings.Title = title;
config.GeneratorSettings.Description = description;
});
app.UseSwaggerWithApiExplorer(config =>
{
config.GeneratorSettings.OperationProcessors.TryGet<ApiVersionProcessor>().IncludedVersions = new[] { "2.0" };
config.SwaggerRoute = "v2.0.json";
config.GeneratorSettings.Title = title;
config.GeneratorSettings.Description = description;
});
app.UseSwaggerUi3(config =>
{
config.SwaggerRoutes.Add(new SwaggerUi3Route("v1.0", "/v1.0.json"));
config.SwaggerRoutes.Add(new SwaggerUi3Route("v2.0", "/v2.0.json"));
});
}
}
And this is one of the controllers (Machines)
```c#
[ApiVersion("1.0")]
[SwaggerTag("Machines", Description = "Core operations on machines.")]
public class MachinesController : BaseController
{
[HttpGet("{id:long}")]
[ProducesResponseType((int)HttpStatusCode.OK)]
public async Task
{
return await Mediator.Send(new GetMachineByIdQuery() { Id = id });
}
[HttpGet]
[ProducesResponseType((int)HttpStatusCode.OK)]
public async Task<ActionResult<List<Machine>>> List()
{
return await Mediator.Send(new GetMachineListQuery());
}
[HttpPost]
[ProducesResponseType((int)HttpStatusCode.Created)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> Create(MachineCreateModel machine)
{
if (machine == null)
return BadRequest();
long newId = await Core.CreateMachine(machine);
return CreatedAtAction(nameof(Get), new { id = newId }, null);
}
[HttpPut]
[ProducesResponseType((int)HttpStatusCode.Accepted)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> Update(long id, Machine machine)
{
if (machine == null || machine.Id != id)
{
return BadRequest();
}
await Mediator.Send(new MachineUpdateCommand { Machine = machine });
return AcceptedAtAction(nameof(Get), new { id = id }, machine);
}
[HttpPost]
public async Task<IActionResult> NormalizeConfiguration(int machineId)
{
await Core.MachineNormalizeConfiguration(machineId);
return Ok();
}
[HttpPost]
public async Task<IActionResult> Start(int machineId)
{
await Core.MachineStart(machineId);
return Ok();
}
[HttpPost]
public async Task<IActionResult> Stop(int machineId)
{
await Core.MachineStop(machineId);
return Ok();
}
}
```
I'd say UseSwagger() is Swashbuckle and not NSwag, so you need to check in the Swashbuckle docs why this happens, right?
@RSuter Sorry! My fault! I was missing the code of MY UseSwagger() extension method!!! 馃槢
I've updated the previous post. Please take a look now... Thanks!
@RSuter I've just updated to latest version (11.19.2) but the problem still remains.
What am I doing wrong?
I've noticed just now, that the default content-type selected on the dropdowns is different for GET and POST/PUT. So for GETs there's "text/plain" and for POSTs/PUTs "application/json" instead.
@RSuter Hi!
I'm now on v11.20.1, but the problem is still there.
As described in my last comment
the default content-type selected on the dropdowns is different for GET and POST/PUT. So for GETs there's "text/plain" and for POSTs/PUTs "application/json" instead



I think it can be a matter of configuration... can we investigate further?
Did you check the generated swagger.json? There you will see text/plain somewhere.. can you post that?
Here it is my JSON.
There's "text/plain" as first value of produces list in the /api/Machines/Get method.
{
"x-generator": "NSwag v11.20.1.0 (NJsonSchema v9.11.0.0 (Newtonsoft.Json v11.0.0.0))",
"swagger": "2.0",
"info": {
"title": "Control API",
"description": "API for Core functionalities.",
"version": "1.0.0"
},
"host": "localhost:5001",
"schemes": [
"http"
],
"consumes": [
"application/json-patch+json",
"application/json",
"text/json",
"application/*+json"
],
"paths": {
"/api/v1.0/Machines/Get/{id}": {
"get": {
"tags": [
"Machines"
],
"operationId": "Machines_Get",
"produces": [
"text/plain",
"application/json",
"text/json"
],
"parameters": [
{
"type": "integer",
"name": "id",
"in": "path",
"required": true,
"format": "int64",
"x-nullable": false
}
],
"responses": {
"200": {
"x-nullable": true,
"description": "",
"schema": {
"$ref": "#/definitions/Machine"
}
}
}
}
},
"/api/v1.0/Machines/Create": {
"post": {
"tags": [
"Machines"
],
"operationId": "Machines_Create",
"consumes": [
"application/json-patch+json",
"application/json",
"text/json",
"application/*+json"
],
"parameters": [
{
"name": "machine",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/MachineCreateModel"
},
"x-nullable": false
}
],
"responses": {
"201": {
"description": ""
},
"400": {
"description": ""
}
}
}
},
"/api/v1.0/Machines/Update": {
"put": {
"tags": [
"Machines"
],
"operationId": "Machines_Update",
"consumes": [
"application/json-patch+json",
"application/json",
"text/json",
"application/*+json"
],
"parameters": [
{
"type": "integer",
"name": "id",
"in": "query",
"format": "int64",
"x-nullable": false
},
{
"name": "machine",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/Machine"
},
"x-nullable": false
}
],
"responses": {
"202": {
"description": ""
},
"400": {
"description": ""
}
}
}
}
},
"definitions": {
"Machine": {
"type": "object",
"additionalProperties": false,
"required": [
"id",
"status",
"machineDriverId"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"mnmConfiguration": {
"type": "string"
},
"status": {
"$ref": "#/definitions/MachineBootStatus"
},
"machineDriverId": {
"type": "integer",
"format": "int64"
},
"machineDriver": {
"$ref": "#/definitions/MachineDriver"
},
"driverConfiguration": {
"type": "string"
},
"driverStatus": {
"type": "string"
}
}
},
"MachineBootStatus": {
"type": "string",
"description": "",
"x-enumNames": [
"Disabled",
"Stopped",
"Started",
"DriverNotFound",
"InvalidDriverConfig",
"InvalidMnmConfig",
"NoRoutes",
"Failed"
],
"enum": [
"Disabled",
"Stopped",
"Started",
"DriverNotFound",
"InvalidDriverConfig",
"InvalidMnmConfig",
"NoRoutes",
"Failed"
]
},
"MachineDriver": {
"type": "object",
"additionalProperties": false,
"required": [
"id"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"model": {
"type": "string"
},
"signature": {
"type": "string"
}
}
},
"MachineCreateModel": {
"type": "object",
"additionalProperties": false,
"required": [
"machineDriverId"
],
"properties": {
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"mnmConfiguration": {
"type": "string"
},
"phaseName": {
"type": "string"
},
"machineDriverId": {
"type": "integer",
"format": "int64"
}
}
}
},
"tags": [
{
"name": "Machines",
"description": "Core operations on machines."
}
]
}
I temporary solved the problem by simply putting the Produces attribute on the top of all of my controllers, like this:
```c#
[Produces("application/json")]
[ApiVersion("1.0")]
[SwaggerTag("Machines", Description = "Core operations on machines.")]
public class MachinesController : ControllerBase
{ }
### UPDATE 2019/07/23
I forgot to mention that if you are using a common base class for all your Controllers, you can just put the `Produces` attribute only on the base class.
```c#
[ApiController]
[Produces("application/json")]
[Route("api/v{version:apiVersion}/[controller]/[action]")]
public abstract class BaseController : ControllerBase
{
// TODO: Add needed common methods/properties for all Controllers
}
[Authorize]
[ApiVersion("1.0")]
[OpenApiTag("Machines", Description = "Operations on machines")]
public class MachinesController : BaseController
{
// TODO: Add controller methods
}
[Authorize]
[ApiVersion("1.0")]
[OpenApiTag("Machines", Description = "Operations on machines")]
public class DriversController : BaseController
{
// TODO: Add controller methods
}
@RSuter But I don't know if it is really necessary, since you said that should come automatically.
Any news?
Also There are one more temporary resolving way.
Just override Produces on AddSwaggerDocument when add swagger document on startup.cs
services.AddSwaggerDocument(settings =>
{
settings.PostProcess = document => document.Produces = new List<string>
{
"application/json",
"text/json"
};
});
Also There are one more temporary resolving way.
Just override
ProducesonAddSwaggerDocumentwhen add swagger document on startup.csservices.AddSwaggerDocument(settings => { settings.PostProcess = document => document.Produces = new List<string> { "application/json", "text/json" }; });
@js-lee0624
Just a note for users reading the suggestion, from NSwag v13, there was a refactoring, so the method is called AddOpenApiDocument instead of AddSwaggerDocument.
@OculiViridi
you can just put the Produces attribute only on the base class.
I don't think that would be a good idea in many cases as Produces changes the behavior of the application, basically it turns off content negotiation. It might work if you always produce JSON output, but it is definitely not RESTful to ignore the Accept HTTP request header.
Most helpful comment
I temporary solved the problem by simply putting the
Producesattribute on the top of all of my controllers, like this:```c#
[Produces("application/json")]
[ApiVersion("1.0")]
[SwaggerTag("Machines", Description = "Core operations on machines.")]
public class MachinesController : ControllerBase
{ }
@RSuter But I don't know if it is really necessary, since you said that should come automatically.
Any news?