locked
Help Needed in Displaying the output model in Documentation RRS feed

  • Question

  • User1489758560 posted

    Hi,

    Working in Asp.net 2.2 and below are the sample code 

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Runtime.Serialization;
    using System.Threading.Tasks;
    using System.Xml.Serialization;
    
    namespace Swagger_dotnetCore2._2
    {
        public class Util
        {
    public static BaseResponse<T> ConstructAPIBaseResponse<T>(T objResult, MessageModel messageModel)
    {
    return new BaseResponse<T>()
    {
    TResponse = new TResponse<T>(System.Net.HttpStatusCode.OK)
    {
    Result = objResult,
    TMessage = messageModel,
    StatusCode = System.Net.HttpStatusCode.OK
    }
    }; ;
    }
    public static MessageModel ConstructMessageModel(short Code, string Description)
    {
    return new MessageModel { Code = Code, Description = Description };
    } } [DataContract] public class TResponse<T> { [DataMember] public string Version { get { return "1"; } } [DataMember] public HttpStatusCode StatusCode { get; set; } [DataMember(EmitDefaultValue = false)] public object Result { get; set; } [DataMember(EmitDefaultValue = false)] public MessageModel TMessage { get; set; } public TResponse(HttpStatusCode statusCode, object result = null, MessageModel messageModel = null) { StatusCode = statusCode; Result = result; TMessage = messageModel; } } public class MessageModel { [DataMember] public short Code { get; set; } [DataMember] public string Description { get; set; } } public class BaseResponse<T> { [DataMember] public TResponse<T> TResponse { get; set; } } public class Member { public string Name { get; set; } public string Age { get; set; } } }

    startup.cs

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.HttpsPolicy;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    using Swashbuckle.AspNetCore.Swagger;
    
    namespace Swagger_dotnetCore2._2
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            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().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    
                // Register the Swagger generator, defining 1 or more Swagger documents
                services.AddSwaggerGen(c =>
                {
                    c.SwaggerDoc("v1", new Info
                    {
                        Version = "v1",
                        Title = "Test Title version 1 ",
                        Description = "Test Description",
                        TermsOfService = "None",
                        Contact = new Contact
                        {
                            Name = "Ali Ben Chaabene",
                            Email = "alibenchaabene@gmail.com",
                            Url = ""
                        }
    
                    });
    
                    c.SwaggerDoc("v2", new Info
                    {
                        Version = "v2",
                        Title = "Test Title version 2 ",
                        Description = "Test Description",
                        TermsOfService = "None",
                        Contact = new Contact
                        {
                            Name = "Ali Ben Chaabene",
                            Email = "alibenchaabene@gmail.com",
                            Url = ""
                        }
    
                    });
    
                    //Locate the XML file being generated by ASP.NET...
                    var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.XML";
                    var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
    
                    //... and tell Swagger to use those XML comments.
                    c.IncludeXmlComments(xmlPath);
                    //c.DocumentFilter<SwaggerAuthorizationFilter>();
                });
                services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                    app.UseHsts();
                }
    
                //app.UseSwaggerAuthorized();
                // Enable middleware to serve generated Swagger as a JSON endpoint.
                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", "API Test Version 1");
                    c.SwaggerEndpoint("/swagger/v2/swagger.json", "API Test Version 2");
                });
    
    
                app.UseHttpsRedirection();
                app.UseMvc();
            }
        }
    }
    

    Values Controller:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    
    namespace Swagger_dotnetCore2._2.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class ValuesController : ControllerBase
        {
    
            /// <summary>
            /// Get all values
            /// </summary>
            /// <remarks>
            /// Here is a sample remarks placeholder.
            /// </remarks>
            /// <returns>A list of string</returns>
            [HttpGet]
    [ProducesResponseType(typeof(BaseResponse<Member>), 200)]
    public ActionResult<IEnumerable<string>> Get()
    {
    return Ok(Util.ConstructAPIBaseResponse(new Member { Name="Test",Age="12" },null ));
    } } }

    i am trying to display the output model schema of my api call in the  swagger and i found i have to use "ProducesResponseType". but i have custom response binding.

    when  i run the project to see swagger model schema response, i am getting the below 

    {
      "tResponse": {
        "version": "1",
        "statusCode": 200,
        "result": {}
      }
    }

    But i need the result of swagger model  schema response as

    {
      "tResponse": {
        "version": "1",
        "statusCode": 200,
        "result": {
          "name": "",
          "age": ""
        }
      }
    }

    am not sure where am doing the mistake. please help me in solving this issue.

    Tuesday, September 1, 2020 8:51 PM

Answers

  • User711641945 posted

    Hi born2win,

    Use generic types could maximize code reuse.It could get the same response with different class.What you want goes against the generic type rule.

    To achieve what you want,you could only create a new single class for Bad Request:

    public class BadResponse<T>
    {
        public HttpStatusCode StatusCode { get; set; }
        [DataMember(EmitDefaultValue = false)]
        public object Result { get; set; }
        [DataMember(EmitDefaultValue = false)]
        public MessageModel TMessage { get; set; }
        public BadResponse(HttpStatusCode statusCode, object result, MessageModel messageModel = null)
        {
            StatusCode = statusCode;
            Result = result;
            TMessage = messageModel;
        }
    }

    Controller:

    [HttpGet]
    [ProducesResponseType(typeof(BaseResponse<Member>), 200)]
    [ProducesResponseType(typeof(BadResponse<MessageModel>), 400)]
    
    public ActionResult<IEnumerable<string>> Get()
    {
        return Ok(Util.ConstructAPIBaseResponse(new Member { Name = "Test", Age = "12" }, null));
    }

    Best Regards,

    Rena

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, September 4, 2020 8:16 AM

All replies

  • User475983607 posted

    You should rethink the design.  The version is in the request URL and the the status code is in the HTTP response.   Clients that uses your Web API will expect a standard REST response.  For example, a 201 tells the client to look at the location header for the newly created resource URL. A 404 tells the client the resource does not exist.    It's unexpected to return a 200 and force the client to always look at the HTTP body to figure out what happened.  

    Tuesday, September 1, 2020 9:25 PM
  • User1489758560 posted

    Thank you for the response and this is a sample code i did fast to illustrate my issue. your point is absolutely valid. i will fix that. But please help in solving the actual issue that i am unable to bring the response example to be displayed in swagger documentation as like i needed.

    i am getting like this 

    {
      "tResponse": {
        "version": "1",
        "statusCode": 200,
        "result": {}
      }
    }

    but i need to display like 

    {
      "tResponse": {
        "version": "1",
        "statusCode": 200,
        "result": {
          "name": "",
          "age": ""
        }
      }
    }

    so that who ever consumes the api wanted to see the documentation to see the sample output response, can refer this. Please help me in this.

    Wednesday, September 2, 2020 1:24 AM
  • User711641945 posted

    Hi born2win,

    I used asp.net core version 3.1 with Swashbuckle.AspNetCore version 5.5.1.

    Change your model design like below:

    public class Util
    {
        public static BaseResponse<T> ConstructAPIBaseResponse<T>(T objResult, MessageModel messageModel)
        {
            return new BaseResponse<T>()
            {
                TResponse = new TResponse<T>(HttpStatusCode.OK, objResult,null)
                {
                    Result = objResult,
                    TMessage = messageModel,
                    StatusCode = HttpStatusCode.OK
                }
            }; ;
        }
        public static MessageModel ConstructMessageModel(short Code, string Description)
        {
            return new MessageModel { Code = Code, Description = Description };
        }
    }
    [DataContract]
    public class TResponse<T>
    {
        [DataMember]
        public string Version { get { return "1"; } }
    
        [DataMember]
        public HttpStatusCode StatusCode { get; set; }
    
        [DataMember(EmitDefaultValue = false)]
        public T Result { get; set; }
    
        [DataMember(EmitDefaultValue = false)]
        public MessageModel TMessage { get; set; }
    
        public TResponse(HttpStatusCode statusCode, T result, MessageModel messageModel = null)
        {
            StatusCode = statusCode;
            Result = result;
            TMessage = messageModel;
        }
    }
    
    public class MessageModel
    {
        [DataMember]
        public short Code { get; set; }
    
        [DataMember]
        public string Description { get; set; }
    }
    
    public class BaseResponse<T>
    {
        [DataMember]
        public TResponse<T> TResponse { get; set; }
    }
    
    public class Member
    {
        public string Name { get; set; }
        public string Age { get; set; }
    }

    Best Regards,

    Rena

    Wednesday, September 2, 2020 9:28 AM
  • User1489758560 posted

    Hi Rena,

    Thanks a lot for the reply and i am able to get the result as expected. but there is a small issue in this. for 200 response this is good. but for 400 response i want the result as empty.

    Current : 

    {
      "tResponse": {
        "version": "string",
        "statusCode": 100,
        "result": {
          "code": 0,
          "description": "string"
        },
        "tMessage": {
          "code": 0,
          "description": "string"
        }
      }
    }

    Expected output:

    {
      "tResponse": {
        "version": "string",
        "statusCode": 400,
        "result": {  },
        "tMessage": {
          "code": 0,
          "description": "string"
        }
      }
    }
    [HttpGet]
            [ProducesResponseType(typeof(BaseResponse<Member>), 200)]
            [ProducesResponseType(typeof(BaseResponse<MessageModel>), 400)]
            public ActionResult<IEnumerable<string>> Get()
            {
                return  Ok(Util.ConstructAPIBaseResponse(new Member { Name="Test",Age="12" },null ));
                // string[] { "value1", "value2" };
            }

    i tried as like below, but not workig

     public TResponse(HttpStatusCode statusCode, T result , MessageModel messageModel = null)
            {
                StatusCode = statusCode;
                if (!object.Equals(result, default(T)))
                {
                    Result = result;
                }
                
                TMessage = messageModel;
            }

    Please help me in this regard how to achieve in the case of 400

    Wednesday, September 2, 2020 12:55 PM
  • User711641945 posted

    Hi born2win,

    Did you use my whole code?It could work well in my project:

    What is your asp.net core and Swashbuckle.AspNetCore version version?Are they same as my previous post said?

    Best Regards,

    Rena

    Thursday, September 3, 2020 6:45 AM
  • User1489758560 posted

    Hi Rena,

    Thanks for the reply and  for 200 response its working. for the 400 response, the result must be empty  as like below

    {
      "tResponse": {
        "version": "string",
        "statusCode": 400,
        "result": {  },
        "tMessage": {
          "code": 0,
          "description": "string"
        }
      }
    }

    How do i achieve this please

    Thursday, September 3, 2020 6:00 PM
  • User711641945 posted

    Hi born2win,

    Use generic types could maximize code reuse.It could get the same response with different class.What you want goes against the generic type rule.

    To achieve what you want,you could only create a new single class for Bad Request:

    public class BadResponse<T>
    {
        public HttpStatusCode StatusCode { get; set; }
        [DataMember(EmitDefaultValue = false)]
        public object Result { get; set; }
        [DataMember(EmitDefaultValue = false)]
        public MessageModel TMessage { get; set; }
        public BadResponse(HttpStatusCode statusCode, object result, MessageModel messageModel = null)
        {
            StatusCode = statusCode;
            Result = result;
            TMessage = messageModel;
        }
    }

    Controller:

    [HttpGet]
    [ProducesResponseType(typeof(BaseResponse<Member>), 200)]
    [ProducesResponseType(typeof(BadResponse<MessageModel>), 400)]
    
    public ActionResult<IEnumerable<string>> Get()
    {
        return Ok(Util.ConstructAPIBaseResponse(new Member { Name = "Test", Age = "12" }, null));
    }

    Best Regards,

    Rena

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, September 4, 2020 8:16 AM
  • User475983607 posted

    The design also goes against REST standards.

    Saturday, September 5, 2020 6:03 AM