Reputation: 534
I am trying to add swagger+swashbuckle to my ASP.NET Core project. I can get the Swagger UI up and running but it is completely empty. I tried poking around and found a similar problem at https://github.com/domaindrivendev/Swashbuckle/issues/1058. This made me think that maybe the routing was the issue so I tried giving my controller an explicit route using [Route("testroute")]
over the method but not the class. This made the endpoints I added a route to show up with no problem.
As adding an explicit route to every endpoint is non-optimal, what am I doing wrong and how do I fix it to get swagger to show all my endpoints?
My startup where swagger is integrated
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true , reloadOnChange: true);
Configuration = builder.Build();
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
// Register the Swagger generator, defining one or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
});
services.AddDbContext<PromotionContext>(options => options.UseSqlServer(Configuration["ConnectionStrings:Jasmine"]));
services.AddTransient<PromotionDbInitializer>();
services.AddTransient<IComponentHelper, ComponentHelper>();
services.AddTransient<IComponentFileHelper, ComponentFileHelper>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, PromotionDbInitializer promotionSeeder)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Promotion}/{action=Index}/{id?}");
});
//Because there is not a seed method built into the EF migrations pipeline in EFCore this seeding method will interfere with the migrations when attempting to deploy the database
//uncomment if you need to seed
//promotionSeeder.Seed().Wait();
}
}
My controller where the GetAll and Post method show up on the swagger ui page under testroute and testFormRoute, but the Get and Delete methods do not show up
public class PromotionController : Controller
{
private PromotionContext context;
public PromotionController(PromotionContext _context)
{
context = _context;
}
public IActionResult Index()
{
return View();
}
[HttpGet]
[Route("testroute")]
public IActionResult GetAll()
{
try
{
var result = context.Promotions
.Include(promotion => promotion.CombinabilityType)
.Include(promotion => promotion.ValueType)
.Include(promotion => promotion.Currency)
.Include(promotion => promotion.Components)
.ThenInclude(component => component.TargetType)
.ToList();
return Ok(result);
}
catch(Exception ex)
{
return StatusCode(500);
}
}
public IActionResult Get(string promoCode)
{
try
{
var result = context.Promotions
.Include(promotion => promotion.CombinabilityType)
.Include(promotion => promotion.ValueType)
.Include(promotion => promotion.Currency)
.Include(promotion => promotion.Components)
.ThenInclude(component => component.TargetType)
.FirstOrDefault(x => x.PromoCode == promoCode);
return Ok(result);
}
catch(Exception ex)
{
return StatusCode(500);
}
}
[HttpPost]
[Route("testFormRoute")]
public IActionResult Post([FromForm] Promotion newPromotion)
{
try
{
context.Promotions.Add(newPromotion);
context.SaveChanges();
}
catch(DbUpdateException ex)
{
return StatusCode(500);
}
return Ok();
}
[HttpDelete]
public IActionResult Delete(string promoCode)
{
try
{
var promotion = context.Promotions.FirstOrDefault(x => x.PromoCode == promoCode);
if(promotion != null)
{
context.Promotions.Remove(promotion);
context.SaveChanges();
}
}
catch(DbUpdateException ex)
{
return StatusCode(500);
}
return Ok();
}
}
Upvotes: 0
Views: 4500
Reputation: 1016
Add a route attribute to your controller:
[Route("[controller]/[action]")]
public class PromotionController : Controller
{
...
And set the HttpGet attribute on your actions:
[HttpGet]
public IActionResult GetAll()
{
...
[HttpGet("{promoCode}")]
public IActionResult Get(string promoCode)
{
...
You have to be careful about how you mix and match static and dynamic routes. Check out this article for more detail about attribute based routing in asp.net core.
Upvotes: 5
Reputation: 461
Try changing
public class PromotionController : Controller
to
public class PromotionController : ApiController
Upvotes: -1