Open Closed

How to use Swagger API versioning with tiered project #1894


User avatar
0
uyarbtrlp created

Hello ABP,

We are trying to implement API versioning with tiered project. We use URI versioning for realizing that. We have checked your test project for api versioning. Also we have checked https://github.com/abpframework/abp/issues/3315 issue. We are able to create two different versions of our API. I can see clearly on Swagger. We cannot see all APIs relevant with ABP's modules such as Identity, Permission Management. We added HttpApi modules in PreConfigureServices for seeing on swagger. . We inserted account admin and account public as an example.

First question is what we have done is best practice for seeing the controllers related with ABP?

After inserting api versioning logic, web module crashed.

Host and Identity project work with no problem. Exception message is below. Swagger configuration code:

private void ConfigureSwagger(ServiceConfigurationContext context, IConfiguration configuration)
        {
            Configure<AbpAspNetCoreMvcOptions>(options => { context.Services.ExecutePreConfiguredActions(options); });
            context.Services.AddControllers();
            context.Services.AddAbpApiVersioning(options =>
            {
                options.DefaultApiVersion = new ApiVersion(1, 0);
                options.AssumeDefaultVersionWhenUnspecified = true;
                options.ReportApiVersions = true;
                options.ApiVersionReader = new UrlSegmentApiVersionReader();

                var mvcOptions = context.Services.ExecutePreConfiguredActions<AbpAspNetCoreMvcOptions>();
                options.ConfigureAbp(mvcOptions);


            });

            context.Services.AddVersionedApiExplorer(options =>
            {
                // add the versioned api explorer, which also adds IApiVersionDescriptionProvider service
                // note: the specified format code will format the version as "'v'major[.minor][-status]"
                options.GroupNameFormat = "'v'VVV";

                // note: this option is only necessary when versioning by url segment. the SubstitutionFormat
                // can also be used to control the format of the API version in route templates
                options.SubstituteApiVersionInUrl = true;
            });
            context.Services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
            context.Services.AddSwaggerGen(options =>
            {
                options.OperationFilter<SwaggerDefaultValues>();
                options.DocumentFilter<CustomSwaggerFilter>();
                options.DocInclusionPredicate((docName, description) =>
                {
                    // Get api major version
                    var apiVersion = $"v{description.GetApiVersion().MajorVersion}";

                    if (!docName.Equals(apiVersion))
                        return false;

                    // Replace router parameter
                    var values = description.RelativePath
                        .Split('/')
                        .Select(v => v.Replace("v{version}", apiVersion));

                    description.RelativePath = string.Join("/", values);

                    return true;
                });
                options.CustomSchemaIds((type) => type.FullName);
                options.SchemaFilter<AddEnumSchemaFilter>();

            });
        }

Hello controller code :

using System.Threading.Tasks;
using ApiVersioningTiered.Controllers;
using Microsoft.AspNetCore.Mvc;

namespace Volo.Abp.AspNetCore.Mvc.Versioning.App
{
    [ApiVersion("1.0")]
    [ApiVersion("2.0")]
    [ApiController]
    [Route("api/v{version:apiVersion}/[controller]")]
    public class HelloController : ApiVersioningTieredController
    {
        [HttpGet]
        public Task<string> GetAsync()
        {
            return Task.FromResult($"Get");
        }

        [HttpPost]
        [Route("Test")]
        [MapToApiVersion("1.0")]
        public Task<string> PostAsyncV1()
        {
            return PostAsync();
        }

        [HttpPost]
        [MapToApiVersion("2.0")]
        [Route("Test")]
        public Task<string> PostAsyncV2()
        {
            return PostAsync();
        }

        private Task<string> PostAsync()
        {
            return Task.FromResult($"Post-{HttpContext.GetRequestedApiVersion().ToString()}");
        }
    }
}

Are there any suggestions about that?

  • ABP Framework version: v4.2.2
  • UI type: MVC
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): yes
  • Exception message and stack trace:
* AbpException: Could not found remote action for method: System.Threading.Tasks.Task`1[Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationConfigurationDto] GetAsync() on the URL: https://localhost:44321/
Volo.Abp.Http.Client.DynamicProxying.ApiDescriptionFinder.FindActionAsync(HttpClient client, string baseUrl, Type serviceType, MethodInfo method)
Volo.Abp.Http.Client.DynamicProxying.DynamicHttpProxyInterceptor&lt;TService&gt;.MakeRequestAsync(IAbpMethodInvocation invocation)
Volo.Abp.Http.Client.DynamicProxying.DynamicHttpProxyInterceptor&lt;TService&gt;.MakeRequestAndGetResultAsync&lt;T&gt;(IAbpMethodInvocation invocation)
Volo.Abp.Http.Client.DynamicProxying.DynamicHttpProxyInterceptor&lt;TService&gt;.GetResultAsync(Task task, Type resultType)
Volo.Abp.Http.Client.DynamicProxying.DynamicHttpProxyInterceptor&lt;TService&gt;.InterceptAsync(IAbpMethodInvocation invocation)
Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter&lt;TInterceptor&gt;.InterceptAsync&lt;TResult&gt;(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func&lt;IInvocation, IInvocationProceedInfo, Task&lt;TResult&gt;> proceed)
Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous&lt;TResult&gt;(IInvocation invocation, IInvocationProceedInfo proceedInfo)
Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue&lt;TResult&gt;.ProceedAsync()
Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter&lt;TInterceptor&gt;.InterceptAsync&lt;TResult&gt;(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func&lt;IInvocation, IInvocationProceedInfo, Task&lt;TResult&gt;> proceed)
Volo.Abp.AspNetCore.Mvc.Client.MvcCachedApplicationConfigurationClient.&lt;GetAsync&gt;b__14_0()
Volo.Abp.Caching.DistributedCache&lt;TCacheItem, TCacheKey&gt;.GetOrAddAsync(TCacheKey key, Func&lt;Task&lt;TCacheItem&gt;> factory, Func&lt;DistributedCacheEntryOptions&gt; optionsFactory, Nullable&lt;bool&gt; hideErrors, bool considerUow, CancellationToken token)
Volo.Abp.AspNetCore.Mvc.Client.MvcCachedApplicationConfigurationClient.GetAsync()
Volo.Abp.AspNetCore.Mvc.Client.RemoteLanguageProvider.GetLanguagesAsync()
Microsoft.AspNetCore.RequestLocalization.DefaultAbpRequestLocalizationOptionsProvider.GetLocalizationOptionsAsync()
Microsoft.AspNetCore.RequestLocalization.AbpRequestLocalizationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
Microsoft.AspNetCore.Builder.UseMiddlewareExtensions+&lt;&gt;c__DisplayClass6_1+&lt;&lt;UseMiddlewareInterface&gt;b__1>d.MoveNext()
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

8 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Can you share your app source code wihe me?

    liming.ma@volosoft.com

  • User Avatar
    0
    uyarbtrlp created

    Hi,

    I sent the source code

  • User Avatar
    0
    EngincanV created
    Support Team .NET Developer

    Hi, Can you change your UseSwaggerUI middleware as follows?

    app.UseSwaggerUI(options => 
    {  
        // builds a swagger endpoint for each API version  
        foreach (var description in provider.ApiVersionDescriptions)  
        {  
            options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());  
        }  
        
        var configuration = context.GetConfiguration();
        options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]);
        options.OAuthClientSecret(configuration["AuthServer:SwaggerClientSecret"]);
    }); 
    
  • User Avatar
    0
    uyarbtrlp created

    Hi,

    it is already like that

     app.UseSwaggerUI(options =>
                {
                    options.DocumentTitle = "NMM API";
    
                    // Display latest api version by default
                    //
                    var provider = context.ServiceProvider.GetRequiredService<IApiVersionDescriptionProvider>();
                    foreach (var description in provider.ApiVersionDescriptions)
                    {
                        options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
                    }
                    var configuration = context.GetConfiguration();
                    options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]);
                    options.OAuthClientSecret(configuration["AuthServer:SwaggerClientSecret"]);
                });
    
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    I will check your project asap.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Please remove the options.ConventionalControllers.Create(typeof(AbpAccountAdminHttpApiModule).Assembly,...

    You cannot change the API version in the module. You can only control your own API.

    Add below to HttpApi.Host project.

    context.Services.Configure<ApiVersioningOptions>(options =>
    {
        options.UseApiBehavior = false;
    });
    

    Add below to Web project.

    context.Services.AddApiVersioning();
    
  • User Avatar
    0
    uyarbtrlp created

    Hi,

    Thank you.

  • User Avatar
    0
    EngincanV created
    Support Team .NET Developer

    Hi @uyarbtrlp, as I see your problem is resolved so I close the question. If your problem is not resolved yet, please don't hesitate to re-open it.

Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11