127

I develop an ASP.NET Core 2 application and included Swagger. Everything worked fine until I introduced a method without explicitly defining the HTTP action:

public class ErrorController : Controller
{
    [Route("/error")]
    public IActionResult Index()
    {
        return StatusCode(500, new Error("Internal error."));
    }
}

When I started the app with this method, the following message showed up:

Failed to load API definition.

Errors
Fetch error Internal Server Error /swagger/v1/swagger.json

As soon as I explicitly set e.g. [HttpGet] the error disappears. The problem with this is, I need this method to fire for all possible HTTP operations. Of course, I could specify all operations explicitly, but I have the feeling Swagger should be able to handle this correctly.

Why does Swagger behave this way?

Is there any configuration I can use?

Community
  • 1
  • 1
Ash
  • 3,283
  • 6
  • 16
  • 20
  • 1
    ' I need this method to fire for all possible HTTP operations' why will you need to support all methods, rather than only GET? – Set May 07 '18 at 09:06
  • Can you share your Swashbuckle configuration? – Helder Sepulveda May 07 '18 at 19:50
  • @Set in this case the `Error` endpoint is used as the exception handler. Depending on the HTTP operation of the request, the according operation on the `Error` endpoint is called. – Ash May 08 '18 at 08:09
  • 1
    @HelderSepu the config is pretty straight forward: `services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Info { Title = "My Service", Version = "v1" }); }); app.UseSwagger(c => { c.PreSerializeFilters.Add((swagger, httpReq) => swagger.Host = httpReq.Host.Value); }); app.UseSwaggerUI(c => { c.RoutePrefix = "swagger"; // serve the UI at root c.SwaggerEndpoint("/swagger/v1/swagger.json", "V1 Docs"); });` – Ash May 08 '18 at 08:11
  • I managed to reproduce your issue, looks like a Bug in the Swashbuckle.AspNetCore, the `ResolveConflictingActions` should work – Helder Sepulveda May 08 '18 at 13:58
  • @HelderSepu the code you provided in your comment above worked for me. I'm using Swashbuckle.AspNetCore(3.0.0) and AspNetCore.All(2.0.9). – Weej Aug 21 '18 at 15:11

36 Answers36

109

Add Httpxxx([HttpGet], [HttpPost], ...) attribute for each Action method, or [ApiExplorerSettings(IgnoreApi = true)]

LiKui
  • 1,099
  • 2
  • 6
  • 2
82

Simply you can look into the log in the Output window. The actual error can be seen there. In my case, I missed adding HTTP action on top of a methods

enter image description here

Hossein Narimani Rad
  • 31,361
  • 18
  • 86
  • 116
43

Instead of blindy guessing what could be the issue, navigate to

http://localhost:PORT/swagger/v1/swagger.json

enter image description here

In my case this could have been resolved by using the c.CustomSchemaIds(x => x.FullName);

which is a horrible workaround, but might be a quick fix for someone in need. My solution was to rename and clarify the path for those endpoints

Justin
  • 115
  • 4
rjso
  • 1,314
  • 10
  • 19
  • 7
    This helped me a lot! Navigated to http://localhost:PORT/swagger/v1/swagger.json and got a much more detailed error message. – JohanThorild Jan 20 '21 at 09:59
  • Same as @JohanThorild - the JSON error message pointed to a public method in my controller that Swagger thought was an API call. Changed it to private -- fixed! – Thane Plummer Jun 14 '21 at 21:21
  • correct, must navigate to json location to get error message – toha Apr 20 '22 at 09:54
41

The option ResolveConflictingActions should be working on this case...

Here is the actual error:

System.NotSupportedException: Ambiguous HTTP method for action

That is coming from: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/86cc761bc4f5dda796f80ad8dfd8bc205542a6f6/src/Swashbuckle.AspNetCore.SwaggerGen/Generator/SwaggerGenerator.cs#L90

I think this is a bug, if you are truly interested you should report it to the project

Helder Sepulveda
  • 15,500
  • 4
  • 29
  • 56
  • 5
    For ASP.net core 3 I had to add the ResolveConflictingActions into my AddSwaggerGen section in startup > c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); – Paddymac Nov 02 '19 at 19:28
  • 1
    Yups, in my case I kept same URL for two different APIs. – Soni Vimalkumar Jul 23 '20 at 10:58
  • 1
    In my case, I defined two [HttpGet] in my ApiController and Swagger get confused, but if I define [HttpGet("myMethod1")] and [HttpGet("myMethod2")], then, swagger understands. I see ResolveConflictingActions only as a patch. Hope that it helps. – Aquiles Apr 20 '21 at 13:21
21

I don't know if this has been resolved or not but one way you can go about this is by decorating the method with:

[ApiExplorerSettings(IgnoreApi = true)]

This will ensure that the method in question is ignored by Swagger.

Moshood Aminu
  • 271
  • 1
  • 5
16

Another possible issue is that the endpoint needs to be complete from the domain root.

I had:

app.UseSwaggerUI(c =>
{
     c.SwaggerEndpoint("/swagger/v1/swagger.json", "V1 Docs");
});

I had to use:

 app.UseSwaggerUI(c=>
{
     c.SwaggerEndpoint("/myApi/swagger/v1/swagger.json", "V1 Docs");

});
Erick
  • 1,176
  • 15
  • 25
  • 4
    another solution is to use `c.SwaggerEndpoint("v1/swagger.json", "V1 Docs");`. This should work for both relative and absolute urls. – pawellipowczan Jul 27 '20 at 10:31
  • 1
    this is what i caused my issue – Carlo Luther Feb 05 '21 at 19:55
  • This `c.SwaggerEndpoint("v1/swagger.json", "V1 Docs");` worked for me. – Md Farid Uddin Kiron Oct 09 '21 at 05:04
  • Same here, I added the leading '/' and it worked. Not sure why though, my other microservices don't have it. `opts.SwaggerEndpoint("/v1/download/swagger.json", "Download");` Edit: It looks like it was a trailing '/' on one of my controllers. ` [Route("api/v1/my-endpoint/")]` – Donkoid Dec 09 '22 at 02:21
13

In ASP.NET Core, if there is a controller endpoint like:

[Route("images")]
[HttpGet("{id}")]

This can also fail with fetch failed. The solution is to have something like

[HttpGet("images/{id}")]

Same thing goes for HttpPost.

dansc
  • 219
  • 3
  • 12
10

In addition to Helder Sepulvedas answer and from 'Monte-Christos' answer in this github issue - Actions require unique method/path combination for Swagger

I found the place to configure ResolveConflictingActions in ASP.NET Core apps. In your Setup class, add this to the ConfigureServices() method:

services.AddSwaggerGen(c => 
  { 
    other configs...;
    c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
  });

This done the trick for me!

Paddymac
  • 377
  • 1
  • 3
  • 19
6

Swagger also throws the same exception if there are public methods that are not actions in a controller. The fix is to make all of them protected or private or as mentioned add the attribute [ApiExplorerSettings(IgnoreApi = true)].

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
  • 3
    I had a base class to the controllers with a public helper function and your suggestion solved the issue by making it `protected`. – ΩmegaMan Jan 26 '19 at 21:50
5

in my case i use this code as like as .net code

[ActionName("Login")]
[HttpPost]

now i change it for use on net core web api

[HttpPost("Login")]

And it works right

hossein andarkhora
  • 740
  • 10
  • 23
4

The default api controller route configuration is the cause of this issue. When we add the API controller in the ASP.NET Core API application, by default it has controller-specific routes, which means it can support only a single method for each of the HTTP verbs Post, PUT, Delete, GET, and Patch.

There may be a requirement when we need to create more than one method having the Http verbs Post, PUT, Delete, GET, and Patch in a single controller, and if you create the method with the default route configuration, then you will get the following error while loading the Swagger UI.

enter image description here

The solution is that you have to change the default route configuration at the controller level when you have created more than one method with the HTTP verbs "post," "put," and "get." Delete or Put in the single API controller class.

Consider the following example: I have created the ASP.NET Core API application, which has by default one Get method, GetWeatherForecast, which returns the WeatherForecast. Then I have added one more Get method named WeatherForecastByCity in the default API Controller class without modifying the default route.

 [ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
        _logger = logger;
    }

    [HttpGet(Name = "GetWeatherForecast")]
    public IEnumerable<WeatherForecast> Get()
    {
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToArray();
    }

    [HttpGet(Name = "WeatherForecastByCity")]
    public IEnumerable<WeatherForecast> Get(string city)
    {
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

When we have run the application, we will get the Swagger loading error,

enter image description here

Now change the default route at controller level which can support more than one method having the Http verbs Post, PUT, Delete, GET, and Patch in a single controller.

[Route("api/[controller]/[action]")]

Also, remove the name of the method from the HTTP verb, which is defined using the Name attribute; just define the HTTP verb and proper method name.

Change from

 [HttpGet(Name = "GetWeatherForecast")]
    public IEnumerable<WeatherForecast> Get()
    {
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToArray();
    }

To

 [HttpGet]
    public IEnumerable<WeatherForecast> GetWeatherForecast()
    {
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToArray();
    }

Full Code

 [ApiController]
[Route("api/[controller]/[action]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
        _logger = logger;
    }

    [HttpGet]
    public IEnumerable<WeatherForecast> GetWeatherForecast()
    {
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToArray();
    }

     [HttpGet]
    public IEnumerable<WeatherForecast> WeatherForecastByCity(string city)
    {
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

Now, run the application again after changing the default route, and you will see swagger loads without any issue.

enter image description here

vithal wadje
  • 155
  • 10
3

I had the same issue. In my case, All of my controllers inherited from a BaseController. in this base class, I got a public action which returns UserId according to Claims. I set the [NonAction] attribute on the top of this action.

[ApiController]
[ApiResultFilter]
[Route("api/[controller]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

public class BaseController : ControllerBase
{

    [NonAction]
    public int GetCurrentUserId()
    {
        return int.Parse(this.User.Claims.First(p => p.Type == ClaimTypes.NameIdentifier).Value);
    }
}
Matt Qafouri
  • 1,449
  • 2
  • 12
  • 26
3

Guess what... started getting this error page "Failed to load API definition":

enter image description here

By looking at the app's console or the output window in Visual Studio it told me the following:

enter image description here

I added a public method called Client to the Web API BaseController and Swagger was thinking it should be included in the API.

To solve the problem: mark that method as protected:

enter image description here

Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
3

This is answer 32 so there is a variety of reasons!

-> You need to troubleshoot efficiently

Solutions differ from some only working for NSwag/Swashbuckle to different versions of Swashbuckle to adding JsonIgnore of Newtonsoft vs built in or adding the BindNever attribute which all might or might not help but for sure it costs time!

Before you start: Check if there is maybe an exception or error message in debug console. This might speed you up the most. Sometimes there is none!

Speedy troubleshooting guide:

  1. All your Controllers should have a [ApiController] attribute (if not consider adding it) so search and replace [ApiController] with [ApiController][ApiExplorerSettings(IgnoreApi = true)] to make them invisible for SwaggerGen

OptionA - Working now without any api controllers:

  1. Open your favorite Git tool that has a user interface and dismiss half of the changes in git until swagger loads https://127.0.0.1:12345/swagger/index.html again and that way rule it down to a single controller that breaks swashbuckle
  2. Comment out all Get/Post/Put/Delete actions within this single controller and check if it is working.
  3. Comment back in half of that actions until it is no longer working and that way rule it down to a single action
  4. Comment out the whole content of the Action and just return Ok(); to see if response is the problem.
  5. Try with a replacement request class that just has a fraction of the props and narrow it down to a property causing the problem.

OptionB - Still not working even without any api controllers:

  1. Try to reproduce with a fresh minimal project using the same package version and make the new project more and more similar to your big one. Your problem is likely already the initialisation which might be broken e.g. due to breaking changes or incompatibility within packages.

When you have the root cause the solution is often obvious

Possible root causes I have seen:

  • A property of type "Type" in the request POCO which was failing without leaving any hint about what the problem is. The solution was to change it to a function which even made more sense than how it was.
  • A class with the same name in 2 different namespaces

If you know how to improve this guide write it in the comments.

CodingYourLife
  • 7,172
  • 5
  • 55
  • 69
2

I was also getting this error because i created a controller which dosent have [Route("api/[controller]")]. After putting it, the error went away.

app.UseSwagger()
   .UseSwaggerUI(c =>
   {
       c.SwaggerEndpoint("/swagger/v1/swagger.json", "DOA.API V1");
   });
prisar
  • 3,041
  • 2
  • 26
  • 27
2

Double check , if you have used same url name in your same controller. It was happened to my code

B.Nishan
  • 536
  • 4
  • 13
2

What worked for me is adding [NonAction] attribute to the public methods that are not API calls in my controller wrapper.

z-boss
  • 17,111
  • 12
  • 49
  • 81
  • 1
    In my case, public method from my BaseController should have change from public to protected. But your method was inspiration for me. – ohdev Apr 14 '20 at 22:24
1

My error reason was that same url name,

 [HttpGet("get/LeaveCommand/{id}")]

I use same url and swagger cannot get them

 [HttpGet("get/LeaveCommand/{id}")]
Ergin Çelik
  • 719
  • 7
  • 14
1

I also had this problem. I checked and applied all of the solutions for swagger config but the issue still remained. Finally, I checked the output panel and the problem was because of [DefaultValue("SYSDATETIMEOFFSET()")].

The answer is here: Check the output panel and you will find the answer

Fateme Mirjalili
  • 762
  • 7
  • 16
1

I was getting below error in .net core web api:

Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorException: Failed to generate Operation for action - WebApplication9.Controllers.AnimalsController.Post (WebApplication9). See inner exception

Solution:

Make sure to use the different class/name per models, I was passing the same name with different properties. So swagger json schemas wasn't identifying the correct one.

Example:

UserController.cs

[HttpPost, Route("Create")]
public IActionResult Create(CreateRequest model) {}

PersonController.cs

[HttpPost, Route("Create")]
public IActionResult Create(CreateRequest model) {}

So, we need to use different models as parameter such as UserCreateRequest and PersonCreateRequest.

immayankmodi
  • 8,210
  • 9
  • 38
  • 55
1

When you use Swagger is necessary to add [ApiExplorerSettings(IgnoreApi = true)] in your code like this:

    [Route("/error")]
    [ApiExplorerSettings(IgnoreApi = true)]
    public IActionResult HandleError() =>
        Problem();
1

I've got the error mentioned in the question and didn't find in answers the simple reason like:

Endpoints should have unique routes i.e. distinct by name, VERB etc.

enter image description here

Swagger is struggled when 2 endpoints routs looks the same

Check recently added endpoint(s) if they are not duplicating from routing perspective (name, verbs etc.)

in my case i was experimenting and did a copy-paste like this:

enter image description here

once i've made them distinct routes, Swagger was ok

enter image description here

the solution is simply specify a unique route

Artem Vertiy
  • 1,002
  • 15
  • 31
0

I was getting a TypeLoadException on a class that I was deleting that was unused. The fix in my case was to delete the bin/obj/Debug folder contents. Clean solution + rebuild solution did not fix for me.

daniel.caspers
  • 1,660
  • 1
  • 18
  • 22
0

It happened because of Newtonsoft.Json in my case. But the thing is I was not using it. One of the packages may be depend on it but I did not have time to check.

So just check the output panenl solve the related issue.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
keremercan
  • 41
  • 1
  • 4
0

If you have in your models (request or response) properties of type which inherits/implements types like System.ComponentModel (or other types) this will throw an error

"The JSON property 'item' is defined multiple times on type"...

Try to ignore this property using [JsonIgnore] attribute of Newtonsoft.Json

In my case i had a getter of type DataTable

abdelgrib
  • 843
  • 7
  • 11
0

In the Startup file you need to make sure that you add

services.AddSwaggerDocument();

before you add

app.UseOpenApi();
app.UseSwaggerUi3();

or it can result in this error

Fetch error undefined /swagger/{documentName}/swagger.json

Ricky Keane
  • 1,540
  • 2
  • 15
  • 21
0

for core 3 I had the same issue and was really confused that problem was in slash.

Configuration was:

services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "my-API", Version = "v1" });
            });

This swagger endpoint threw the message of TS:

app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/v1/swagger.json", "my-API v1");
            });

And finally I got it worked with removing the first slash in the URL:

app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("v1/swagger.json", "my-API v1");
            });
Ustin
  • 568
  • 6
  • 19
0

For me the problem was having registering swagger after MapControllers middleware. Once I moved before it worked.

sensei
  • 7,044
  • 10
  • 57
  • 125
0

For me it was a very simple issue, i had 3 [HttpGet] methods which turned out i needed to change the "createOrder" method to a [HttpPost]

        [HttpGet]
        public async Task<ActionResult<List<Order>>> GetOrders()
        {
            return await _context.Orders.Include(o => o.OrderItems).Where(x => x.BuyerId == User.Identity.Name).ToListAsync();
        }

        [HttpGet("{id}", Name = "GetOrder")]
        public async Task<ActionResult<Order>> GetOrder(int id)
        {
            return await _context.Orders.Include(x => x.OrderItems).Where(x => x.BuyerId == User.Identity.Name && x.Id == id).FirstOrDefaultAsync();
        }

        [HttpPost]
        public async Task<ActionResult<int>> CreateOrder(CreateOrderDto orderDto)
        {
            var basket = await _context.Baskets.RetrieveBasketWithItems(User.Identity.Name).FirstOrDefaultAsync();
            var items = new List<OrderItem>();
}
Zina
  • 41
  • 2
0

For me it was solved by adding the HttpGet attribute and removing the index methods.

0

The issue for me was caused by lazy/frustrated refactoring and I was able to determine the issue by reading the debug console when running the API in debugger mode.

Due to the bad refactoring, I ended up with two models with the same name, and Swagger was getting confused.

I had something like:

PROJECT
├───Auth
│       AutheController.cs
│       UserDto.cs
│
└───Controllers
    │   MyContrller.cs
    │
    └───Models
            UserDto.cs

Having two UserDto models is what was confusing Swagger. Cleaning this up fixed the issues.

Michael Murphy
  • 1,921
  • 2
  • 18
  • 21
0

enter image description here

And the logs.....

System.ArgumentOutOfRangeException: Count cannot be less than zero. (Parameter 'count')

And in my case, the Route definition was wrong.

Before (returns error) Note the lack of {curly braces} in the Route definition.

[HttpGet]
[Route("id:guid")]

After (all good - no error)

[HttpGet]
[Route("{id:guid}")]
nspire
  • 1,567
  • 23
  • 26
0

Make sure you methods in controller are marked with [HttPost] and/or [HttpGet]

FarrukhMalik
  • 129
  • 1
  • 2
0

use the [HttpGet("Post")] or [HttpGet("Get")] in your Actions

0

I found out that using enums in your object class (get, put, or post) also causes this issue.

By removing the line below in my

AddJsonOptions

I had it resolved.

options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
Ismail Hassani
  • 442
  • 5
  • 14
0

The reason that I encountered for this error was the same API name for 2 methods in the same controller.

I suffixed the other method to _v2 and the swagger opened up properly.

enter image description here

enter image description here

enter image description here

Cheers, Tanjot

Tanjot
  • 31
  • 4
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/34781502) – Siddharth Seth Aug 06 '23 at 16:12