aspnetboilerplate: ApiVersioning + Swagger + ApplicationService not working

Hi I try to use ApiVersioning for dynamic web api But this doesn’t work reference:https://github.com/microsoft/aspnet-api-versioning/blob/master/samples/aspnetcore/SwaggerSample/Startup.cs

ApplicationService

 [ApiVersion("1.0")]
 public class TestAppService: ApplicationService, ITestAppService
    {
        public Task<string> Get()
        {
           return  Task.FromResult("Test");
        }
    }

Startup.cs

           services.AddApiVersioning(options =>
            {
                options.ReportApiVersions = true;
                options.ApiVersionReader = new HeaderApiVersionReader("Api-Version");
                options.AssumeDefaultVersionWhenUnspecified = true;
                options.DefaultApiVersion = new ApiVersion(1, 0);
            });
            services.AddVersionedApiExplorer(options =>
            {
                options.AssumeDefaultVersionWhenUnspecified = true;
                options.DefaultApiVersion = new ApiVersion(1, 0);
                options.GroupNameFormat = "'v'VVV";
            });

apiVersioning and swagger cannot find TestAppService on abp 5.5.0.0

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 16 (6 by maintainers)

Most upvoted comments

Hi @vcluopeng thanks for answering.

Hi @ismcagdas,

I managed to add API versioning to asp.net Zero. If you think there is more easier or better way to achieve this, I would happy to here. If you think it is ok, can we have this as part of documentation of asp.net zero (.netcore + angular)

File ProjectName.Web.Host\startup\startup.cs method ConfigureServices changed related code to this:

if (WebConsts.SwaggerUiEnabled)
  {
      //Swagger - Enable this line and the related lines in Configure method to enable swagger UI
      services.AddSwaggerGen(options =>
      {
          options.SwaggerDoc("v1.0", new OpenApiInfo() { Title = "ProjectName API", Version = "v1.0" });
          // if needed add swagger version like following
          options.SwaggerDoc("v2.0", new OpenApiInfo() { Title = "ProjectName API", Version = "v2.0" });
          options.SwaggerDoc("v3.0", new OpenApiInfo() { Title = "ProjectName API", Version = "v3.0" });

          options.DocInclusionPredicate((docName, apiDesc) =>
          {
              if (!apiDesc.TryGetMethodInfo(out MethodInfo methodInfo)) return false;

              IEnumerable<ApiVersion> versions = new List<ApiVersion>();

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

              if (!versions.Any())
                  versions = methodInfo.DeclaringType
                                  .GetCustomAttributes(true)
                                  .OfType<ApiVersionAttribute>()
                                  .SelectMany(attr => attr.Versions).ToList();

              return versions.Count() == 0 || versions.Any(v => $"v{v}" == docName && apiDesc.RelativePath.Contains($"v{v}"));
          });

          options.ParameterFilter<SwaggerEnumParameterFilter>();
          options.SchemaFilter<SwaggerEnumSchemaFilter>();
          options.OperationFilter<SwaggerOperationIdFilter>();
          options.OperationFilter<SwaggerOperationFilter>();
          options.CustomDefaultSchemaIdSelector();
          options.EnableAnnotations();

          var basePath = AppContext.BaseDirectory;
          foreach (var name in Directory.GetFiles(basePath, "*.XML", SearchOption.AllDirectories))
              options.IncludeXmlComments(name);

      }).AddSwaggerGenNewtonsoftSupport();
  }

File ProjectName.Web.Host\startup\startup.cs in Configure method changed code to this:

if (WebConsts.SwaggerUiEnabled)
     {
         // Enable middleware to serve generated Swagger as a JSON endpoint
         app.UseSwagger();
         // Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)

         app.UseSwaggerUI(options =>
         {
             options.SwaggerEndpoint(_appConfiguration["App:SwaggerEndPoint"], "ProjectName API V1");
             // if needed add swagger version like following
            //addreses can be add to appsetting.json
             options.SwaggerEndpoint("/swagger/v2.0/swagger.json", "ProjectName API V2");
             options.SwaggerEndpoint("/swagger/v3.0/swagger.json", "ProjectName API V3");

             options.IndexStream = () => Assembly.GetExecutingAssembly()
                 .GetManifestResourceStream("XX.Web.wwwroot.swagger.ui.index.html");
             options.InjectBaseUrl(_appConfiguration["App:ServerRootAddress"]);
         }); //URL: /swagger
     }

File ProjectName.Web.Core.ProjectNameCoreModule.cs In PreInitialize method changed code to this:

Comment or remove following lines

            //Configuration.Modules.AbpAspNetCore()
            //    .CreateControllersForAppServices(
            //        typeof(ProjectNameApplicationModule).GetAssembly()
            //    );

And add these line to be able adding apppservice as controller with version in url:

var moduleName = "app";
  Configuration.Modules.AbpAspNetCore()
  .CreateControllersForAppServices(typeof(ProjectNameApplicationModule).GetAssembly(), moduleName)
  .ConfigureControllerModel(model =>
  {
      foreach (var action in model.Actions)
      {
          List<ApiVersion> controllerVersions = new List<ApiVersion>();
          if (action.Attributes.Any(x => x is ApiVersionAttribute))
          {
              controllerVersions = action.Attributes.OfType<ApiVersionAttribute>().SelectMany(x => x.Versions).ToList();
          }
          else if (action.Controller.Attributes.Any(x => x is ApiVersionAttribute))
          {
              controllerVersions = action.Controller.ControllerType.GetCustomAttributes(true)
                  .OfType<ApiVersionAttribute>().SelectMany(x => x.Versions).ToList();

          }

          if (controllerVersions.Any())
          {
              foreach (var version in controllerVersions.Select(x => x.ToString()).ToList())
              {
                  var selectorModel = new SelectorModel
                  {
                      AttributeRouteModel = new AttributeRouteModel(
                          new RouteAttribute(
                              $"api/v{version}/services/{moduleName}/{action.Controller.ControllerName}/{action.ActionName}"
                          )
                      )
                  };

                  selectorModel.ActionConstraints.Add(new HttpMethodActionConstraint(new List<string>
                              {ProxyScriptingHelper.GetConventionalVerbForMethodName(action.ActionName)}));

                  action.Selectors.Add(selectorModel);
              }
          }

      }
  });

Change appsettingjson.json

`"SwaggerEndPoint": "/swagger/v1/swagger.json", ->`  `"SwaggerEndPoint": "/swagger/v1.0/swagger.json",`

Add version Info to AppService or methods:

    [ApiVersion("1.0")]
    [ApiVersion("2.0")]

    [AbpAuthorize(AppPermissions.Pages_AddressToContacts)]
    public class AddressSystemAppService : ProjectNameAppServiceBase, IAddressSystemAppService
    {
      // ....

        [ApiVersion("3.0")]
        public async Task<ListResultDto<GetCountryForViewDto>> GetAllCountries()
        {
            var countries = await _countryRepository.GetAllIncluding(p => p.Translations).ToListAsync();
            return new ListResultDto<GetCountryForViewDto>(ObjectMapper.Map<List<GetCountryForViewDto>>(countries));
        }

   // ....
    }

Note: To get latest APı methods in nswag In file ProjectName.Web.Host\nswag\service.config.nswag change following: "url": "https://localhost:44301/swagger/v1/swagger.json", --> "url": "https://localhost:44301/swagger/v1.0/swagger.json", Or change to desired version "url": "https://localhost:44301/swagger/v3.0/swagger.json",

Now versioning works as expected.

V1 image

V2 image

V3 image