Skip to content

Update ApiControllerBase.cs#11

Open
Soruk wants to merge 1 commit into
thomasduft:mainfrom
Soruk:patch-1
Open

Update ApiControllerBase.cs#11
Soruk wants to merge 1 commit into
thomasduft:mainfrom
Soruk:patch-1

Conversation

@Soruk

@Soruk Soruk commented Dec 8, 2021

Copy link
Copy Markdown

Add Attribute "ApiController" in order to generate Swagger documentation

[ApiController]

Add Attribute  [ApiController] in order to generate Swagger documentation
@Soruk

Soruk commented Dec 8, 2021

Copy link
Copy Markdown
Author

I think it might be usefull also to add grouping of APIby project

 [ApiExplorerSettings(GroupName = "Name-Group")]

@thomasduft

thomasduft commented Dec 9, 2021

Copy link
Copy Markdown
Owner

Hi Soruk

Is having the ApiController-attribute a requirement in order to generate Swagger documentation or will it enrich the generated documentation with additional information? Honestly I do not know the details here. I thought it should be already be possible with what is there at the moment.

Regarding the ApiExplorerSettings-attribute, this is already set directly on the specific endpoint-Controllers (see the below picture).

image

And yes, they are hardcoded strings meaning an integrator can not change it to his will. Any suggestions on this?

@Soruk

Soruk commented Dec 9, 2021

Copy link
Copy Markdown
Author

Hi @thomasduft, the ApiController-attribute is mandatory to generate the Swagger documentation.
When I reference your nugets for the use with Swagger (btw the included XML documentation is not complete) I do not have any endpoints exposed by your API. I had the same issue with my main executing assemble, and when I added the given attribute, the Swagger documentation was generated for given endpoint.

@thomasduft

Copy link
Copy Markdown
Owner

Hi @Soruk

This is weird?! When I use and reference my latest published nuget openiddict-ui packages and setup the Swagger related stuff within the Startup/Program.cs file then I see the endpoints and I can also browse them.

image

I usually develop within devcontainers on a linux based PC with VSCode. So to me the ApiController-attribute doesn't seem to be mandatory.

@Soruk

Soruk commented Dec 9, 2021

Copy link
Copy Markdown
Author

Hi @thomasduft

Yes it is weird.
Can you share your Startup/Program.cs, please ?

@thomasduft

thomasduft commented Dec 9, 2021

Copy link
Copy Markdown
Owner

Et voilà...

using System.Reflection;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerUI;

using tomware.Suite.Host.Web;
using tomware.Suite.Persistence.EF;

var configuration = new ConfigurationBuilder()
  .AddJsonFile("appsettings.json")
  .Build();

var builder = WebApplication.CreateBuilder(args);

// Add services to the container => ConfigureServices
builder.Services.Configure<StorageContextOptions>(options =>
{
  options.DbContextOptionsBuilder = builder =>
     builder.UseSqlite(configuration.GetConnectionString("DefaultConnection"),
       sql => sql.MigrationsAssembly(typeof(Program)
                 .GetTypeInfo()
                 .Assembly
                 .GetName()
                 .Name));
});

builder.Services.AddModules();

if (builder.Environment.IsDevelopment())
{
  builder.Services.AddSwaggerGen(c =>
  {
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "App", Version = "v1" });
    c.DocInclusionPredicate((name, api) => true);
    c.TagActionsBy(api =>
    {
      if (api.GroupName != null)
      {
        return new[] { api.GroupName };
      }

      var controllerActionDescriptor = api.ActionDescriptor as ControllerActionDescriptor;
      if (controllerActionDescriptor != null)
      {
        return new[] { controllerActionDescriptor.ControllerName };
      }

      throw new InvalidOperationException("Unable to determine tag for endpoint.");
    });
    c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
  });
}

// Configure
var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
  app.UseCors(builder =>
  {
    builder.WithOrigins("http://localhost:4200");
    builder.AllowAnyHeader();
    builder.AllowAnyMethod();
    builder.AllowCredentials();
  });

  app.UseDeveloperExceptionPage();
  app.UseSwagger();
  app.UseSwaggerUI(c =>
  {
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "App v1");
    c.DocExpansion(DocExpansion.None);
  });
}

app.UseWebAppWithDefaults();

app.Run();

It is part of private stuff and already on .NET 6. But you should see the swagger configuration section....

@Soruk

Soruk commented Dec 9, 2021

Copy link
Copy Markdown
Author

Thanks.

I will check it tomorrow

@Soruk

Soruk commented Dec 10, 2021

Copy link
Copy Markdown
Author

Ok, I have just tested your code, and still I get only the main / executing assembly api endpoints. I do not know why I cannot to get to show the api exposed by referenced assemblies.

@thomasduft

thomasduft commented Dec 10, 2021

Copy link
Copy Markdown
Owner

Same as well if you clone this repo and start the sample server? I can run it on a Linux based PC and a Windows based PC and always see the Swagger generated docs!

@Soruk

Soruk commented Dec 10, 2021

Copy link
Copy Markdown
Author

I have just re-downloaded the code from main branch and I can see the other assemblies documentation.
When I was using the code downloaded just after release of 1.3 version, the swagger didn't work. But it works, strange...
I will be investigating and keep you posted.

@Soruk

Soruk commented Dec 10, 2021

Copy link
Copy Markdown
Author

Hi @thomasduft, I think that I found the source of the problem.
When I use

services.AddVersionedApiExplorer();

for versioning API, and the Controller does not have the given attribute [ApiController], the Swagger documentation is not generated.

I will check this solution from StackOverflow

@Soruk

Soruk commented Dec 10, 2021

Copy link
Copy Markdown
Author

I will check this solution from StackOverflow

And it seems that UseApiBehavior = false is the solution.

@Soruk

Soruk commented Dec 10, 2021

Copy link
Copy Markdown
Author

After more investigation, when I want to filer by version the methods in the following Swagger configration:

   options.DocInclusionPredicate((version, desc) =>
                {
                    if (string.IsNullOrWhiteSpace(desc.GroupName))
                        return false;

                    if (!desc.TryGetMethodInfo(out MethodInfo methodInfo))
                        return false;

                    var versions = methodInfo.DeclaringType
                    .GetCustomAttributes(true)
                    .OfType<ApiVersionAttribute>()
                    .SelectMany(attr => attr.Versions);

                    var maps = methodInfo
                    .GetCustomAttributes(true)
                    .OfType<MapToApiVersionAttribute>()
                    .SelectMany(attr => attr.Versions)
                    .ToArray();

                    return versions.Any(v => $"v{v}" == version)
                    && (!maps.Any() || maps.Any(v => $"v{v}" == version));
                });

without the [ApiVersion], the filter return false.

A little tweak, fix it:

   options.DocInclusionPredicate((version, desc) =>
                {
                    if (string.IsNullOrWhiteSpace(desc.GroupName))
                        return false;

                    if (!desc.TryGetMethodInfo(out MethodInfo methodInfo))
                        return false;

                    var versions = methodInfo.DeclaringType
                    .GetCustomAttributes(true)
                    .OfType<ApiVersionAttribute>()
                    .SelectMany(attr => attr.Versions);

                    var maps = methodInfo
                    .GetCustomAttributes(true)
                    .OfType<MapToApiVersionAttribute>()
                    .SelectMany(attr => attr.Versions)
                    .ToArray();

                       return !versions.Any()  // without version attribute
                        ||
                        (   versions.Any(v => $"v{v}" == version)
                        && (!maps.Any() || maps.Any(v => $"v{v}" == version))
                    );
                });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants