Swagger italicizing quotes - c#

Following remarks in the XML comments section in my code show up in Swagger -
/// <remarks>
/// {
/// "your_val": "1a",
/// "member": "Test"
/// }
///</remarks>
I am noticing that the last value (in this case Test) always has italicized quotations (Red arrow). Does anyone know how to change it to be regular quotes? For example, like they are for 1a (Blue arrow).

Add a remarks element to the Create action method documentation. It supplements information specified in the summary element and provides a more robust Swagger UI. The remarks element content can consist of text, JSON, or XML.
So, in order to fix the remarks and generate the Swagger documentation in a proper way, you must add a text after open the remarks tag, add a break line, and then add an example of request.
Another important detail is the indentation, you must apply a proper code indentation.
Please, find below your current scenario, a fix for your problem, and 2 examples.
Before - Wrong (your scenario)
/// <remarks>
/// {
/// "your_val": "1a",
/// "member": "Test"
/// }
After - Correct
/// <remarks>
/// [Description]:
///
/// {
/// "your_val": "1a",
/// "member": "Test"
/// }
///</remarks>
Example 01:
/// <summary>
/// Creates a Item From Query (Default)
/// </summary>
/// <remarks>
/// Sample request:
///
/// POST /api/Items/CreateViaQuery
/// {
/// "code": "0001",
/// "description": "Item1"
/// }
///
/// </remarks>
/// <param cref="CreateItemViewModel" name="createItemViewModel">Create Item View Model</param>
/// <returns>A newly created Item</returns>
/// <response code="201">Returns the newly created item</response>
/// <response code="400">If the item is null</response>
[HttpPost("CreateViaQuery")]
[ProducesResponseType((int)HttpStatusCode.Created)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public ActionResult<CreateItemViewModel> CreateViaQuery(CreateItemViewModel createItemViewModel)
{
if (!ModelState.IsValid)
{
return BadRequest();
}
return Created("", createItemViewModel);
}
Example 02:
/// <summary>
/// Creates a Item From Body
/// </summary>
/// <remarks>
/// Sample request:
///
/// POST /api/Items/CreateViaBody
/// {
/// "code": "0001",
/// "description": "Item1"
/// }
///
/// </remarks>
/// <param cref="CreateItemViewModel" name="createItemViewModel">Create Item View Model</param>
/// <returns>A newly created Item</returns>
/// <response code="201" cref="CreateItemViewModel">Returns the newly created item</response>
/// <response code="400">If the item is null</response>
[HttpPost("CreateViaBody")]
[ProducesResponseType((int)HttpStatusCode.Created)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public ActionResult<CreateItemViewModel> CreateViaBody([FromBody]CreateItemViewModel createItemViewModel)
{
if (!ModelState.IsValid)
{
return BadRequest();
}
return Created("", createItemViewModel);
}
For more info, please take a look the following article:
Get started with Swashbuckle and ASP.NET Core
I hope this can help you.

Related

How to display parameter in Web API help page for request and response body

I want to show request and response body as parameter not as raw data .
For that I have followed Generate Description Fields for Body Parameters answer but not get success , still showing
/// <summary>
/// Gets some very important data from the server.
/// </summary>
/// <param name="reqData">A Test Model</param>
[HttpPost]
public AccountService.GetAccountList_ResponseData GetAccountList([FromBody] AccountService.GetAccountList_ReqestData reqData)
{
}
//--my modal
public class GetAccountList_ReqestData
{
/// <summary>
/// StartDate
/// </summary>
/// <param name="StartDate">Describe parameter.</param>
public string StartDate { get; set; }
}
//---Also enabled
config.SetDocumentationProvider(new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/WebApi.xml")));
You have to add XmlDocs to your class GetAccountList_RequestData
/// <summary>
/// My requestData model
/// </summary>
/// <param name="reqData">The description you want </param>
public class GetAccountList_ReqestData
{
/// <summary>
/// StartDate
/// </summary>
/// <param name="StartDate">Describe parameter.</param>
public string StartDate { get; set; }
}
You followed the steps correctly, however the person asking in the other thread was displaying a property. You on the other hand are asking for an object, which is your class. Therefor the xmldocs of the class will be used to generate the descriptions.

Adding JSON samples with Microsoft.AspNet.WebApi.HelpPage

I've used Microsoft.AspNet.WebApi.HelpPage and C# XML comments to generate Web API documentation for my Web API project, but would like to add JSON samples to each method, and can't figure out how.
Here's my method's XML comment:
/// <summary>
/// Gets data values for a given data key.
/// </summary>
/// <param name="masterAgencyID">The MasterAgencyDivisionID for the desired values.</param>
/// <param name="masterClientID">The MasterClientID for the desired values.</param>
/// <param name="dataKeyCode">The DataKey's code for which values are to be returned.</param>
/// <returns>An object containing two lists: IncludedValues and ExcludedValues.</returns>
/// <example>
/// {
/// "IncludedValues": [
/// {
/// "DataValueID": 644,
/// "DataValueCode": "1000X500",
/// "DataValueShortDescr": "1000X500",
/// "excluded": false
/// },
/// ...
/// ],
/// "ExcludedValues": [
/// {
/// "DataValueID": 644,
/// "DataValueCode": "1000X500",
/// "DataValueShortDescr": "1000X500",
/// "excluded": true
/// },
/// ...
/// ]
/// </example>
Here's the generated webpage for the method:
As you can see, under "Sample:", the page shows "Sample not available."
It obviously isn't reading from the XML tag. What do I have to do to include an example in my API documentation?

Parameter dont have value in webapi

I am trying to call a service through swagger, by passing a parameter in XML format.
Method is hitting, but the passed parameter is blank
Means "xlff" is blank. Do you have clue what wrong i am doing
/// <summary>
/// Get or insert blog comments which is approved based on blogs
/// </summary>
/// <remarks> Get or insert blog comments which is approved based on blogs</remarks>
/// <param name="xlf">The comment.</param>
/// <response code="200">Get approved blog comments</response>
/// <response code="404">Not found</response>
/// <returns>IHttpActionResult</returns>
[Route("api/smartling/ProcessSmartlingTranslation")]
[VersionedRoute("", 1)]
[ResponseType(typeof(HttpResponseMessage))]
[HttpPost]
public IHttpActionResult ProcessSmartlingTranslation([FromBody]xliff xlff)
{
return Content(HttpStatusCode.BadRequest, "Any object");
}
/// <summary>
/// XliffModel created
/// </summary>
public class xliff
{
/// <summary>
/// file getter setter method
/// </summary>
public string file { get; set; }
/// <summary>
/// body getter setter method
/// </summary>
public string body { get; set; }
}
Your parameter content type is application/json, but you're sending xml. You should change the content type to application/xml.

Validation and synchronous commands in CQRS

I like the idea of trying CQRS without event sourcing.
But I'm not sure how to tackle the fact that I need to give user an instant feedback.
This is how my current signup (simplified to understand)
I use Dapper for reads and nHibernate for writes.
signupcontroller.cs
public ActionResult signup(UserCreateModel model)
{
// model validation (email, password strength etc)
if (!ModelState.IsValid)
{
// get back to form and show errors
}
// use service layer to validate against database and create user
var registermodel = _userService.create_user_account(model.username, model.email, model.password);
// service returns and object with several states
if (registermodel.Status == UserRegistrationStatus.Ok)
{
// user registered ok, display thank you or whatever
}
if (registermodel.Status == UserRegistrationStatus.DuplicatedUsername)
{
// duplicated username found, back to form and show errors
}
if (registermodel.Status == UserRegistrationStatus.DuplicatedEmail)
{
// duplicated email found, back to form and show errors
}
// get back to form and show errors
}
Which of the appraoches would be the most CQRS friendly?
Method 1
signupcontroller.cs
public ActionResult signup(UserCreateModel model)
{
// model validation (email, password strength etc)
if (!ModelState.IsValid)
{
// get back to form and show errors
}
// validate duplicated email
bool is_email_duplicated = _read.user_email_exists(model.email);
// duplicated email found, back to form and show errors
// validate duplicated username
bool is_username_duplicated = _read.user_username_exists(model.username);
// duplicated username found, back to form and show errors
// assume all is perfect and dispatch
_commandDispatcher.Dispatch(new CreateUserCommand(model.username, model.email, model.password));
}
What if I need to do the same validation somewhere else in the system (I would have duplicated code)?
I thought about creating ValidationService.
What if command "explodes" for some reason and user will get false feedback?
Method 2
signupcontroller.cs
public ActionResult signup(UserCreateModel model)
{
// model validation (email, password strength etc)
if (!ModelState.IsValid)
{
// get back to form and show errors
}
// dispatch and validate inside the handler, abort execution if validation failed
var command = new CreateUserCommand(model.username, model.email, model.password)
// attached common feedback object to the command and deal with errors
if(command.status == UserRegistrationStatus.DuplicatedUsername)
{
// get back to form and show errors
}
}
Basically inside the handler I cheat and validate (adding extra methods to nHibernate repo).
Method 3
Similar to the first approach, but encapsulating validation and dispatch within UserService
signupcontroller.cs
public ActionResult signup(UserCreateModel model)
{
// model validation (email, password strength etc)
if (!ModelState.IsValid)
{
// get back to form and show errors
}
var feedback = _userService.create_user(model.username, model.email, model.password);
// check for status and return feedback to the user
}
userservice.cs
public Feedback create_user(string username, string email, string password)
{
// validate duplicated email
bool is_email_duplicated = _read.user_email_exists(email);
// duplicated email found, back to form and show errors
// validate duplicated username
bool is_username_duplicated = _read.user_username_exists(username);
// duplicated username found, back to form and show errors
// dispatch command
_commandDispatcher.Dispatch(new CreateUserCommand(username, email, password));
}
I like this approach but I feel it will become a Baklava code.
Generally when using CQRS, you want to use an optimistic approach.
The idea is to validate your input (may it be simple validation against a string format or the uniqueness of an email) before to issue the command.
Obviously, you will double check your data when actually building your Command to make sure your Command is in a valid and safe state (the same applies to every other objects).
Based on this, you can assume your Command is going to dispatch properly and use an optimistic approach to give a positive feedback to your user.
If your CommandHandler fails to handle your Command it is likely to throw an Exception you can catch and notify your user accordingly.
Take the Messenger / Facebook example, when you type and send, the UI let you think everything is going well and your message has been sent, though, if something happens, your UI will be rolled-back.
Like you have seen, there are multiple possible approaches to dealing with the dispatch of a command. Sometimes you will see people use a strict adherence to returning a void from the command handler, but there is also the approach of an ACK/NACK (Acknowledged / Not Acknowledged) response.
The way that I have done this, is that the Dispatch() method of my command handler implementations will always return one of two possible statuses, being either an ACK or a NACK. This tells me whether or not the command that I attempted to dispatch was deemed to be in a state that it could be applied to the system. However, as opposed to a simple enumeration for ACK/NACK, every command is capable of returning an Acknowledgement class. That class contains a state (the ACK/NACK), along with one or more Command Failures. This way, if I have an ACK, I know that the command was received, and I can assume that it will be processed. On the other hand, if I get back a NACK, I have a failure that I can then format and present to the user. At no time, though, am I returning any information related to the post-dispatch state. The failures that I report (and there can be multiple failures for the same command) are entirely based on the data in the command and not related to it being applied to the system.
This all most closely relates to your third example. Where the above approach varies would mainly be that encapsulating the failures and status will allow you to present/track all issues with a command, as opposed to the first failure.
Here are the simple classes/enumeration that I use to accomplish this.
Acknowledgement
namespace Commands
{
using System;
using System.Collections.Generic;
using System.Linq;
/// <summary>
/// Provides an ACK/NACK for an issued <see cref="Command" />. Can represent one of two states,
/// being either Acknowledged or Not Acknowledged, along with the ability to track unhandled faults.
/// </summary>
/// <remarks>
/// ACK/NACK implies a synchronous command execution. Asynchronous commands, while more rarely used,
/// should represent the concept of command acknowledgement through events.
/// </remarks>
public sealed class Acknowledgement
{
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="Acknowledgement"/> class.
/// </summary>
/// <remarks>
/// This is representative of an <see cref="AcknowledgementState.Acknowledged" /> state, with
/// no command failures nor faults.
/// </remarks>
public Acknowledgement()
{
this.State = AcknowledgementState.Acknowledged;
this.CommandFailures = new List<CommandValidationFailure>();
}
/// <summary>
/// Initializes a new instance of the <see cref="Acknowledgement"/> class.
/// </summary>
/// <param name="failures">The command validation failures that led to NACK.</param>
/// <remarks>
/// This is representative of a <see cref="AcknowledgementState.NotAcknowledged" /> state, with
/// at least one command validation failure and no fault.
/// </remarks>
public Acknowledgement(IEnumerable<CommandValidationFailure> failures)
{
this.State = AcknowledgementState.NotAcknowledged;
this.CommandFailures = failures;
}
/// <summary>
/// Initializes a new instance of the <see cref="Acknowledgement"/> class.
/// </summary>
/// <param name="fault">The fault that led to the NACK.</param>
/// <remarks>
/// This is representative of a <see cref="AcknowledgementState.NotAcknowledged" /> state, with
/// a fault and no command validation failures.
/// </remarks>
public Acknowledgement(Exception fault)
{
this.State = AcknowledgementState.NotAcknowledged;
this.Fault = fault;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the command failures that led to a NACK, if any.
/// </summary>
/// <value>
/// The command failures, if present.
/// </value>
public IEnumerable<CommandValidationFailure> CommandFailures { get; }
/// <summary>
/// Gets the fault that led to a NACK, if present.
/// </summary>
/// <value>
/// The fault.
/// </value>
public Exception Fault { get; }
/// <summary>
/// Gets a value indicating whether this <see cref="Acknowledgement" /> is backed by a fault.
/// </summary>
/// <value>
/// <c>true</c> if this instance is reflective of a fault; otherwise, <c>false</c>.
/// </value>
public bool IsFaulted => this.Fault != null;
/// <summary>
/// Gets a value indicating whether this <see cref="Acknowledgement" /> is backed by command validation failures.
/// </summary>
/// <value>
/// <c>true</c> if this instance is reflective of command failures; otherwise, <c>false</c>.
/// </value>
public bool IsInvalid => this.CommandFailures != null && this.CommandFailures.Any();
/// <summary>
/// Gets the state of this instance, in terms of an ACK or NACK.
/// </summary>
/// <value>
/// The state representation.
/// </value>
public AcknowledgementState State { get; }
#endregion
}
}
AcknowledgementState
namespace Commands
{
/// <summary>
/// Provides a simple expression of acknowledgement state (ACK/NACK).
/// </summary>
public enum AcknowledgementState
{
/// <summary>
/// Indicates an ACK that contains no command failures nor a fault.
/// </summary>
Acknowledged,
/// <summary>
/// Indicates a NACK that contains either command failures or a fault.
/// </summary>
NotAcknowledged
}
}
CommandValidationFailure
namespace Commands
{
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
/// <summary>
/// Thrown when on or more violations are found during the attempted execution of a command.
/// </summary>
/// <remarks>
/// In general, this exception is thrown as a guard against non-validation of a command ahead
/// of application. The most feasible scenario is a command handler which attempts to skip
/// validation, prior to execution.
/// </remarks>
[Serializable]
public class CommandValidationException : Exception
{
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="CommandValidationException"/> class.
/// </summary>
/// <param name="violations">The violations leading to this exception being thrown.</param>
public CommandValidationException(List<DomainValidationFailure> violations)
{
this.Violations = violations;
}
/// <summary>
/// Initializes a new instance of the <see cref="CommandValidationException"/> class.
/// </summary>
/// <param name="violations">The violations leading to this exception being thrown.</param>
/// <param name="message">The message to associate with the exception.</param>
public CommandValidationException(List<DomainValidationFailure> violations, string message) : base(message)
{
this.Violations = violations;
}
/// <summary>
/// Initializes a new instance of the <see cref="CommandValidationException"/> class.
/// </summary>
/// <param name="violations">The violations leading to this exception being thrown.</param>
/// <param name="message">The message to associate with the exception.</param>
/// <param name="innerException">The inner exception to associate with this exception.</param>
public CommandValidationException(List<DomainValidationFailure> violations, string message, Exception innerException) : base(message, innerException)
{
this.Violations = violations;
}
/// <summary>
/// Initializes a new instance of the <see cref="CommandValidationException"/> class.
/// </summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
public CommandValidationException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
#endregion
#region Public Properties
/// <summary>
/// Gets the violations associated to this exception.
/// </summary>
/// <value>
/// The violations associated with this exception.
/// </value>
public List<DomainValidationFailure> Violations { get; }
#endregion
}
}

Duplicate parameters output through Swashbuckle/Swagger

Code is further down in the post.
Question: I would like Swashbuckle to generate the following two "GET" requests:
1. mydomain.com/api/books?apikey=12345567891011121314151617181920
2. mydomain.com/api/books/1234?apikey=12345567891011121314151617181920
Swashbuckle does fine on #1 and it works great from the Swagger UI. But for #2, it ends up generating (and calling):
mydomain.com/api/books/{Id}?id=1234&apikey==12345567891011121314151617181920
Needless to say, that GET fails. Swashbuckle is picking up the literal "Id" from the route attribute as well as the BookDetail object. In fact, it shows both IDs in the UI, but I was able to solve that by de-duping by hooking up a custom IOperationFilter, but that obviously didn't help with correcting the actual GET request path.
I already looked at Duplicate parameter output in Swagger 2 but that answer does not work for me. I am looking for having Swashbuckle use the "Id" that's part of the BookDetail object so that Swagger UI shows the description (from the XML comment) while supporting route based ID rather than query string based: mydomain.com/api/books/1234.... What am I doing wrong? (I am on Swashbuckle 5.2.2).
Code:
/// <summary>
/// Books controller
/// </summary>
[RoutePrefix("api")]
public class BooksController : ApiController
{
/// <summary>
/// Returns books matching the search query
/// </summary>
/// <param name="searchRequest"></param>
/// <returns></returns>
[Route("books")]
public IHttpActionResult Get(BookSearch searchRequest)
{
//Do stuff with request
return Ok();
}
/// <summary>
/// Retruns a single book for the given ID
/// </summary>
/// <param name="detailRequest"></param>
/// <returns></returns>
[Route("books/{id:int}")]
public IHttpActionResult Get(BookDetail detailRequest)
{
//Do stuff with request
return Ok();
}
/// <summary>
/// Book search
/// </summary>
public class BookSearch
{
/// <summary>
/// API key
/// </summary>
[Required]
public string ApiKey { get; set; }
/// <summary>
/// Search terms
/// </summary>
public string Query { get; set; }
}
/// <summary>
/// Book detail
/// </summary>
public class BookDetail
{
/// <summary>
/// API key
/// </summary>
[Required]
public string ApiKey { get; set; }
/// <summary>
/// Book of the ID you want to retrieve
/// </summary>
[Required]
public int Id { get; set; }
/// <summary>
/// Boolean indicating whether to include photos or not
/// </summary>
public bool IncludePhotos { get; set; }
}
}

Categories