Base solution for your next web application
Open Closed

Swagger UI Integration #809


0
maharatha created

Hi Hikalkan -

I loved the Swagguer implementation. Thank you a bunch for that. I have a problem in wiring the XML comments with Swagger. I tried someething like this :

.EnableSwagger(c =>
                {
                    c.SingleApiVersion("v1", "XXXXWebApi");
                    c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
                                             
                    c.IncludeXmlComments(@"C:\Source Code\XXX-YYYY\XMLComments\Application Module\AAAAA.BBBBB.Application.XML");
                })
                .EnableSwaggerUi();

Still unable to wire up[ the comments. I used the hard coded path as I am yet to figure out a smart solution to get the comment file path .

Please let me know if I am doing anything wrong


14 Answer(s)
  • 0
    maharatha created

    One more issue I figured out as compared to the below URL :

    <a class="postlink" href="http://www.aspnetboilerplate.com/Pages/Documents/Dynamic-Web-API#naming-convention">http://www.aspnetboilerplate.com/Pages/ ... convention</a>

    This says if your method name starts with Get it will by default use Get http verb, but it doesn't work so. All methods except one or two all are Post

  • 0
    maharatha created

    For now please ignore the issue related to wiring up the comments. I think I am able to do it. Will update this thread with my findings.

  • 0
    ismcagdas created
    Support Team

    Hi,

    Zero is not defined from beginning for http verbs other than POST. Because of that DynamicApiControllerBuilder is not using convetional verbs right now.

    You can add ".WithConventionalVerbs()" to dynamic api controller builder configuration of your project but it might cause problems.

    We can not guarantee that it works.

  • 0
    maharatha created

    Thank You for the clarification. I would rather refrain from using .WithConventionalVerbs() if it's a not a guaranteed work around.

    1. Now coming to the wiring of the XML comments, the comments what's written at the DTO properties are visible in swagger rest are not visible. To describe the isse refer the attached image.

    [attachment=0:3uk9bi1c]Swagger UI.png[/attachment:3uk9bi1c]

    1. How to Omit certain methods ? Basically how to prevent certain methods to be exposed as WebApi ?
  • 0
    ismcagdas created
    Support Team

    Hi,

    1. Can you try writing your comments on AppService interface, not in the AppService class.
    2. You can use Swagger's DocumentFilter for that. An example would be,
    public class FilterRoutesDocumentFilter : IDocumentFilter
    {
        public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
        {
            swaggerDoc.paths["/api/services/app/role/GetRoleForEdit"].post = null;
        }
    }
    

    I hope these help.

  • 0
    maharatha created

    Worked perfect. Thank You so much.

  • 0
    khai created

    Sorry for bringing it up again. I am using ASPNETZero version 5.0.0 (ASPNET Core + Angular). I wrote comments in my interface (ILibraryAppService) but it won't appear on Swagger. Please help me to figure out this.

    /// <summary>Get Single Category object with its children.</summary>
            /// <param name="categoryId">CategoryId</param>
            /// <param name="language">Language Code in 3 characters</param>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task<CategoryOutputWithLanguage> ApiCategoryGetAsync(string categoryId, string tenantId, string language = null, CancellationToken cancellationToken = default(CancellationToken));
    

    <cite>ismcagdas: </cite> Hi,

    1. Can you try writing your comments on AppService interface, not in the AppService class.
    2. You can use Swagger's DocumentFilter for that. An example would be,
    public class FilterRoutesDocumentFilter : IDocumentFilter
    {
       public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
       {
           swaggerDoc.paths["/api/services/app/role/GetRoleForEdit"].post = null;
       }
    }
    

    I hope these help.

  • 0
    ismcagdas created
    Support Team

    Hi @Khai,

    Can you share your app service interface definition ?

  • 0
    khai created

    <cite>ismcagdas: </cite> Hi @Khai,

    Can you share your app service interface definition ?

    Hi @ismcagdas, This is my app service interface.

    public interface ILibraryAppService : IApplicationService
        {
            /// <summary>Get All Categories</summary>
            /// <param name="tenantId">Tenant</param>
            /// <param name="language">Language Code (3-chars - https://www.science.co.il/language/Codes.php) - Required</param>
            /// <param name="buildingId">Building</param>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task<ObservableCollection<CategoryOutputWithLanguage>> ApiCategoryGetAllAsync(string tenantId, string language = null, string buildingId = null, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Create Category</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task ApiCategoryPostAsync(string tenantId, CategoryInput entityInput = null, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Get Single Category object with its children.</summary>
            /// <param name="categoryId">CategoryId</param>
            /// <param name="language">Language Code in 3 characters</param>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task<CategoryOutputWithLanguage> ApiCategoryGetAsync(string categoryId, string tenantId, string language = null, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Update Category</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task ApiCategoryPutAsync(string tenantId, string categoryId, CategoryInput entityInput = null, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Delete category (soft-delete)</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task ApiCategoryDeleteAsync(string tenantId, string categoryId, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Get category object with all languages. Usually used for Get for editing</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task<CategoryOutput> ApiCategoryDetailAsync(string categoryId, string tenantId, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Get All Documents in Category with translated Language</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task<ObservableCollection<DocumentOutputWithLanguage>> ApiDocumentGetAllAsync(string tenantId, string categoryId = null, string language = null, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Create document info object</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task ApiDocumentPostAsync(string tenantId, DocumentInput entityInput = null, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Get single document info with translated language</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task<DocumentOutputWithLanguage> ApiDocumentGetAsync(string documentId, string tenantId, string language = null, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Update Document Info object</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task ApiDocumentPutAsync(string tenantId, string documentId, DocumentInput entityInput = null, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Delete document info (soft-delete)</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task ApiDocumentDeleteAsync(string tenantId, string documentId, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Get single document with all language.
            /// Mostly used for getting data to edit</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task<DocumentOutput> ApiDocumentDetailAsync(string documentId, string tenantId, CancellationToken cancellationToken = default(CancellationToken));
        }
    

    I used NSwag to generate those things to make ASPNETZero become the gateway to my private API (generate HttpClient).

  • 0
    ismcagdas created
    Support Team

    Hi @Khai,

    You need to create the implementation of your App service as well.

  • 0
    khai created

    Hello @ismcagdas, Here is my ILibraryAppService, LibraryAppService. What should I do now?

    1. ILibraryAppService
    public interface ILibraryAppService : IApplicationService
        {
            /// <summary>Get All Categories of Tenant or Building with  Language</summary>
            /// <param name="tenantId">Tenant (Project) - Ex: KRISTA - Required</param>
            /// <param name="language">Language Code (3-chars - https://www.science.co.il/language/Codes.php) - Required</param>
            /// <param name="buildingId">Building - Ex: KRISTA-T1 - Not-Required - Query String</param>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task<ObservableCollection<CategoryOutputWithLanguage>> ApiCategoryGetAllAsync(string tenantId, string language = null, string buildingId = null, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Create Category</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task ApiCategoryPostAsync(string tenantId, CategoryInput entityInput = null, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Get Single Category object with its children.</summary>
            /// <param name="categoryId">CategoryId</param>
            /// <param name="language">Language Code in 3 characters</param>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task<CategoryOutputWithLanguage> ApiCategoryGetAsync(string categoryId, string tenantId, string language = null, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Update Category</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task ApiCategoryPutAsync(string tenantId, string categoryId, CategoryInput entityInput = null, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Delete category (soft-delete)</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task ApiCategoryDeleteAsync(string tenantId, string categoryId, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Get category object with all languages. Usually used for Get for editing</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task<CategoryOutput> ApiCategoryDetailAsync(string categoryId, string tenantId, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Get All Documents in Category with translated Language</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task<ObservableCollection<DocumentOutputWithLanguage>> ApiDocumentGetAllAsync(string tenantId, string categoryId = null, string language = null, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Create document info object</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task ApiDocumentPostAsync(string tenantId, DocumentInput entityInput = null, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Get single document info with translated language</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task<DocumentOutputWithLanguage> ApiDocumentGetAsync(string documentId, string tenantId, string language = null, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Update Document Info object</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task ApiDocumentPutAsync(string tenantId, string documentId, DocumentInput entityInput = null, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Delete document info (soft-delete)</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task ApiDocumentDeleteAsync(string tenantId, string documentId, CancellationToken cancellationToken = default(CancellationToken));
    
            /// <summary>Get single document with all language.
            /// Mostly used for getting data to edit</summary>
            /// <returns>Success</returns>
            /// <exception cref="SwaggerException">A server side error occurred.</exception>
            /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
            Task<DocumentOutput> ApiDocumentDetailAsync(string documentId, string tenantId, CancellationToken cancellationToken = default(CancellationToken));
        }
    
    1. LibraryAppService
    public partial class LibraryAppService : OnePlaceBaseService, ILibraryAppService
        {
            private LibraryHttpClient _libraryClient;
            private string _baseUrl;
    
            public LibraryAppService()
            {
                _baseUrl = "http://localhost:30001";                        
                //_baseUrl = appConfigurationRoot["OnePlaceConfig:URL:LibraryManagement"];
            }
    
            [AbpAuthorize(AppPermissions.Staffs_Library_Category_ReadAll)]
            public async Task<ObservableCollection<CategoryOutputWithLanguage>> ApiCategoryGetAllAsync(string tenantId, string language = null, string buildingId = null,
                CancellationToken cancellationToken = default(CancellationToken))
            {
                _libraryClient = new LibraryHttpClient(_baseUrl, this.GetHttpClient());
                return await _libraryClient.ApiCategoryGetAllAsync(tenantId, language, buildingId, cancellationToken);
            }
    
            [AbpAuthorize(AppPermissions.Staffs_Library_Category_Create)]
            public async Task ApiCategoryPostAsync(string tenantId, CategoryInput entityInput = null,
                CancellationToken cancellationToken = default(CancellationToken))
            {
                _libraryClient = new LibraryHttpClient(_baseUrl, this.GetHttpClient());
                await _libraryClient.ApiCategoryPostAsync(tenantId, entityInput, cancellationToken);
            }
    
            [AbpAuthorize(AppPermissions.Staffs_Library_Category_Read)]
            public async Task<CategoryOutputWithLanguage> ApiCategoryGetAsync(string categoryId, string tenantId, string language = null,
                CancellationToken cancellationToken = default(CancellationToken))
            {
                _libraryClient = new LibraryHttpClient(_baseUrl, this.GetHttpClient());
                return await _libraryClient.ApiCategoryGetAsync(categoryId, tenantId, language, cancellationToken);
            }
    
            [AbpAuthorize(AppPermissions.Staffs_Library_Category_Update)]
            public async Task ApiCategoryPutAsync(string tenantId, string categoryId, CategoryInput entityInput = null,
                CancellationToken cancellationToken = default(CancellationToken))
            {
                _libraryClient = new LibraryHttpClient(_baseUrl, this.GetHttpClient());
                await _libraryClient.ApiCategoryPutAsync(tenantId, categoryId, entityInput, cancellationToken);
            }
    
            [AbpAuthorize(AppPermissions.Staffs_Library_Category_Delete)]
            public async Task ApiCategoryDeleteAsync(string tenantId, string categoryId,
                CancellationToken cancellationToken = default(CancellationToken))
            {
                _libraryClient = new LibraryHttpClient(_baseUrl, this.GetHttpClient());
                await _libraryClient.ApiCategoryDeleteAsync(tenantId, categoryId, cancellationToken);
            }
    
            [AbpAuthorize(AppPermissions.Staffs_Library_Category_Update)]
            public async Task<CategoryOutput> ApiCategoryDetailAsync(string categoryId, string tenantId,
                CancellationToken cancellationToken = default(CancellationToken))
            {
                _libraryClient = new LibraryHttpClient(_baseUrl, this.GetHttpClient());
                return await _libraryClient.ApiCategoryDetailAsync(categoryId, tenantId, cancellationToken);
            }
    
            [AbpAuthorize(AppPermissions.Staffs_Library_Document_ReadAll)]
            public async Task<ObservableCollection<DocumentOutputWithLanguage>> ApiDocumentGetAllAsync(string tenantId, string categoryId = null, string language = null,
                CancellationToken cancellationToken = default(CancellationToken))
            {
                _libraryClient = new LibraryHttpClient(_baseUrl, this.GetHttpClient());
                return await _libraryClient.ApiDocumentGetAllAsync(tenantId, categoryId, language, cancellationToken);
            }
    
            [AbpAuthorize(AppPermissions.Staffs_Library_Document_Create)]
            public async Task ApiDocumentPostAsync(string tenantId, DocumentInput entityInput = null,
                CancellationToken cancellationToken = default(CancellationToken))
            {
                _libraryClient = new LibraryHttpClient(_baseUrl, this.GetHttpClient());
                await _libraryClient.ApiDocumentPostAsync(tenantId, entityInput, cancellationToken);
            }
    
            [AbpAuthorize(AppPermissions.Staffs_Library_Document_Read)]
            public async Task<DocumentOutputWithLanguage> ApiDocumentGetAsync(string documentId, string tenantId, string language = null,
                CancellationToken cancellationToken = default(CancellationToken))
            {
                _libraryClient = new LibraryHttpClient(_baseUrl, this.GetHttpClient());
                return await _libraryClient.ApiDocumentGetAsync(documentId, tenantId, language, cancellationToken);
            }
    
            [AbpAuthorize(AppPermissions.Staffs_Library_Document_Update)]
            public async Task ApiDocumentPutAsync(string tenantId, string documentId, DocumentInput entityInput = null,
                CancellationToken cancellationToken = default(CancellationToken))
            {
                _libraryClient = new LibraryHttpClient(_baseUrl, this.GetHttpClient());
                await _libraryClient.ApiDocumentPutAsync(tenantId, documentId, entityInput, cancellationToken);
            }
    
            [AbpAuthorize(AppPermissions.Staffs_Library_Document_Delete)]
            public async Task ApiDocumentDeleteAsync(string tenantId, string documentId,
                CancellationToken cancellationToken = default(CancellationToken))
            {
                _libraryClient = new LibraryHttpClient(_baseUrl, this.GetHttpClient());
                await _libraryClient.ApiDocumentDeleteAsync(tenantId, documentId, cancellationToken);
            }
    
            [AbpAuthorize(AppPermissions.Staffs_Library_Category_Update)]
            public async Task<DocumentOutput> ApiDocumentDetailAsync(string documentId, string tenantId,
                CancellationToken cancellationToken = default(CancellationToken))
            {
                _libraryClient = new LibraryHttpClient(_baseUrl, this.GetHttpClient());
                return await _libraryClient.ApiDocumentDetailAsync(documentId, tenantId, cancellationToken);
            }
        }
    

    <cite>ismcagdas: </cite> Hi @Khai,

    You need to create the implementation of your App service as well.

  • 0
    ismcagdas created
    Support Team

    Hi,

    Can you try to define your App service like this:

    public partial class LibraryAppService : OnePlaceAppServiceBase, ILibraryAppService
    
  • 0
    khai created

    Hi, I tried and nothing happen...

    <cite>ismcagdas: </cite> Hi,

    Can you try to define your App service like this:

    public partial class LibraryAppService : OnePlaceAppServiceBase, ILibraryAppService
    
  • 0
    ismcagdas created
    Support Team

    @Khai,

    I copied your interface into a new AspNet Zero project and created a dummy imnplementation and I was able to see it on swagger UI. If this is not working for you, please send your project to us via email and let us check it.