Swagger not recognizing JsonProperty("PropertyName") as request property - json.net

I have a web api in .net core3.1 and I am using swagger.
One of my request data class is as below.
public class SNMPv1ReqData{
[JsonProperty("snmpV1Info")]
[MinLength(1)]
[MaxLength(2000)]
[Required]
public List<SNMPv1Info> SNMPv1InfoLst { get; set; }
}
public class SNMPv1Info{
[JsonProperty("host")]
[Required]
public string HostName { get; set; }
[JsonProperty("snmpV1Setting")]
public SNMPv1Setting SNMPv1Setting { get; set; }
[JsonProperty("oid")]
[MinLength(1)]
[MaxLength(1000)]
[Required]
public string[] OID { get; set; }
}
In swagger request is shown as below as it is mentioned in JsonProperty("PropertyName")
{
"snmpV1Info": [
{
"host": "string",
"snmpV1Setting": {
"retryCount": 0,
"timeout": 0,
"port": 0,
"communityName": "string"
},
"oid": [
"string"
]
}
]
}
But when I send request it is showing the below error.
{
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"SNMPv1InfoLst": [
"The SNMPv1InfoLst field is required."
]
}
}
SNMPv1InfoLst is variable name but I want to use "snmpV1Info" in api request which is mentioned in JsonProperty("snmpV1Info") also showing "snmpV1Info" in swagger request.
Startup.cs
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1.0.0", new Microsoft.OpenApi.Models.OpenApiInfo
{
Title = "WebAPI",
Version = "v1.0",
Description = "Edge ASP.NET Core Web API",
});
// Set the comments path for the Swagger JSON and UI.
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
services.AddSwaggerGenNewtonsoftSupport();
Swashbuckle.AspNetCore : 5.6.3
Swashbuckle.AspNetCore.Newtonsoft : 5.6.3
.Net Core3.1
I am not able to find the cause of this problem. Can anyone help me ?

Related

.NET Core doesn't return OData metadata in Responses on Swagger

I'm using swagger in order to generate the endpoints for my React app. In order to do that, I need to specify the response objects for my endpoints and one of my endpoints that has [EnableQuery] annotation, which means is an OData endpoint placed inside an ODataController, doesn't return the right format. What I return now is
{
"ODataContext": "string",
"ODataCount": 0,
"ODataNextLink": "string",
"Value": List<Project>
}
instead of
{
"#odata.context": "string",
"#odata.count": 0,
"#odata.nextLink": "string",
"value": List<Project>
}
I followed this issue from GitHub and the code I used is
[EnableQuery(PageSize = ITEMS_PER_PAGE)]
[ProducesResponseType(typeof(ODataValueWithCount<IEnumerable<Project>>), 200)]
public IQueryable<Project> GetAsync()
{
return _projectRepository.GetProjects();
}
internal class ODataValueWithCount<T> : ODataValue
{
[JsonProperty("#odata.context")]
public string ODataContext { get; set; }
[JsonProperty("#odata.count")]
public int ODataCount { get; set; }
[JsonProperty("#odata.nextLink")]
public string ODataNextLink { get; set; }
[JsonProperty("value")]
public List<Project> Value { get; set; }
}
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Project>("Projects");
return builder.GetEdmModel();
}
but this still somehow returns me the first object that I noted here even though the solution from the issue seems as it's working there. Do you know what am I doing wrong and how can I fix this?
More code from Startup.cs:
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("v1/swagger.json", "MyAPI V1");
});
services.AddSwaggerGen(swagger =>
{
swagger.OperationFilter<ODataOperationFilter>();
swagger.SwaggerDoc("v1", new OpenApiInfo { Title = "API", Version = "0.0.1" });
swagger.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
In = ParameterLocation.Header,
Description = "Please insert JWT with Bearer into field",
Name = "Authorization",
Type = SecuritySchemeType.ApiKey
});
swagger.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] { }
}
});
swagger.ResolveConflictingActions(apiDescription => apiDescription.First());
});

Swagger / Swashbuckle string property options

We have an API in our .Net Core 3.1 project that has a controller which returns a model that is documented by Swagger (Generated by Swashbuckle).
The consumer of the endpoint would like to see the options that a given property may return. For several reasons this for now at least is not just an Enum which would make the process a lot easier. It is a string that can return two different values.
Is there any way to decorate the property so that the options are available in Swagger just as if it had been an Enum? For Enums we can use the MapType on startup, but this is just a string so it's not a type we can map perse.
This is how we have done it with Enums previously:
c.MapType<PaginationSessionType>(() => new OpenApiSchema
{
Type = "string",
Enum = typeof(PaginationSessionType).GetEnumNames()
.Select(name => new OpenApiString(name)).Cast<IOpenApiAny>().ToList()
});
http://swagger-net-test.azurewebsites.net/swagger/ui/index#/TestStringEnum/TestStringEnum_Post
I was able to do what you need with "swagger": "2.0" not 100% sure with the version you are using... At that time I got what I needed with the RegularExpression decorator.
here is the code that generates that:
https://github.com/heldersepu/Swagger-Net-Test/blob/master/Swagger_Test/Controllers/TestStringEnumController.cs
using System.Web.Http;
using System.ComponentModel.DataAnnotations;
namespace Swagger_Test.Controllers
{
public class MyEndpointRequestClass
{
[RegularExpression("^(dark-blue|dark-red|light-blue|light-red)")]
public string StringEnumColor { get; set; }
[RegularExpression("^(high|medium|low)")]
public string Transparency { get; set; }
public string Name { get; set; }
}
public class TestStringEnumController : ApiController
{
public string Post([FromUri] MyEndpointRequestClass r)
{
return r.StringEnumColor;
}
public string Get([RegularExpression("^(uno|due)")]string x)
{
return x;
}
}
}
the relevant swagger.json from that is:
...
"MyEndpointRequestClass": {
"properties": {
"StringEnumColor": {
"type": "string",
"pattern": "^(dark-blue|dark-red|light-blue|light-red)"
},
"Transparency": {
"type": "string",
"pattern": "^(high|medium|low)"
},
"Name": {
"type": "string"
}
},
"xml": {
"name": "MyEndpointRequestClass"
},
"type": "object"
},
...
This might not answer you question but hopefully it sends you on the right direction

Working with restricted string field values in .NET Core WebAPI 3.1

I'm working on a webapi project using .netcore.
I have a model with the following properties:
public class Criterial {
[Required]
public string Field { get; set; }
[Required]
public Operator Operator { get; set; }
[Required]
public string Value { get; set; }
public bool Result { get; set; }
}
public enum Operator {
greater_than,
equal_to,
lower_than
}
I'm trying to use enum to restrict the values that the Operator propertie can receive, but when I make a POST request to the API I got the following scenario:
POST Request Body:
"criterials": [
{
"field": "amount",
"operator": "greater_than",
"value": "50"
}
]
Response from the API:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|7e53377-444fa4a723ac655c.",
"errors": {
"$.criterials[0].operator": [
"The JSON value could not be converted to LeagueOfFateApi.Models.Operator. Path: $.criterials[0].operator | LineNumber: 5 | BytePositionInLine: 26."
]
}
}
Searching about the issue on the internet I found the [JsonConverter(typeof(JsonStringEnumConverter))] Data Annotation.
So I added it to my code and the issue was "solved":
[Required]
[JsonConverter(typeof(JsonStringEnumConverter))]
public Operator Operator { get; set; }
New response from the API:
"criterials": [
{
"field": "amount",
"operator": "greater_than",
"value": "50",
"result": false
}
]
The problem is: in my MongoDB collection a new document was saved with the int value 0 of the enums, and not the string value "greater_than":
"Criterials" : [
{
"Field" : "amount",
"Operator" : 0,
"Value" : "50",
"Result" : false
}
]
Besides, another problem is that the "criterial" field can receive any int value with no restrictions.
Is there any other practical way to restrict a string's options without using enums? Or is there anything I can add to this solution using enums?
Thank you very much for your attention and your time!
According to your description, I suggest you could write custom set and get method for the Operator property.
You could set the Operator's type is string and use Enum.IsDefined to check the Operator value is enum Operator or not.
More details, you could refer to below codes:
public class Criterial
{
[Required]
public string Field { get; set; }
private string _Operator;
[Required]
public string Operator {
get {
return this._Operator;
}
set {
if (Enum.IsDefined(typeof(Operator), value))
{
this._Operator = value;
}
else
{
this._Operator = "Error you used wrong string";
}
}
}
[Required]
public string Value { get; set; }
public bool Result { get; set; }
}
public enum Operator
{
greater_than,
equal_to,
lower_than
}
Result:

Using JSON.Net to parse a property of an array

I have a JSON response that I would like to parse using JSON.NET. I have done this with single values before but never when the response could contain an object that consist of an array as the errors property does below.
{
"code": "InvalidObject",
"message": "payment object is invalid",
"errors": [
{
"code": "AccountingApi",
"message": "Paid amount cannot be greater than the amount of the invoice.",
"resource": "payment",
"field": "amount"
},
{
"code": "AccountingApi",
"message": "Payment has not been verified",
"resource": "payment",
"field": "verification"
}
]
}
I would like to extract the error messages into a List. How do I specify that I want to grab the message property in the errors collection?
List<string> errorMessages = parsedJson["errors"].ToList<string>();
You could use
class Error
{
public string code { get; set; }
public string message { get; set; }
public string resource { get; set; }
public string field { get; set; }
}
class Some
{
public string code { get; set; }
public string message { get; set; }
public List<Error> errors { get; set; }
}
Then (Probably you'll send your json string as param )
List<string> parse()
{
var s = new StringBuilder();
s.Append("{");
s.Append(" \"code\": \"InvalidObject\",");
s.Append("\"message\": \"payment object is invalid\",");
s.Append("\"errors\": [");
s.Append("{");
s.Append("\"code\": \"AccountingApi\",");
s.Append("\"message\": \"Paid amount cannot be greater than the amount of the invoice.\",");
s.Append("\"resource\": \"payment\",");
s.Append("\"field\": \"amount\"");
s.Append("},");
s.Append("{");
s.Append("\"code\": \"AccountingApi\",");
s.Append("\"message\": \"Payment has not been verified\",");
s.Append("\"resource\": \"payment\",");
s.Append("\"field\": \"verification\" ");
s.Append("}");
s.Append("]");
s.Append("}");
var json = s.ToString();
var obj = JsonConvert.DeserializeObject<Some>(json);
return obj.errors.Select(x => x.message).ToList();
}

Asp.Net Wep Api 2 Error When Posting Json Object

I'm developing 3 simple RESTFul services by using ASP.NET Web API 2 and EF6
The name of first service is ImageGallery, which returns ImageGallery json object from Database
I have two entities like these:
ImageGalley.cs:
public class ImageGallery
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Image> Images { get; set; }
}
And Also, Image.cs:
public class Image
{
[Key]
public int ID { get; set; }
public int ImageGalleryID { get; set; }
public string Caption { get; set; }
public string Url { get; set; }
public virtual ImageGallery ImageGallery { get; set; }
}
My Controller's Get method:
public IList<ImageGallery> GetImageGalleries()
{
var imgGalls = db.ImageGalleries.ToList();
return imgGalls;
}
For Post:
[ResponseType(typeof(ImageGallery))]
public IHttpActionResult PostImageGallery(ImageGallery imageGallery)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.ImageGalleries.Add(imageGallery);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = imageGallery.ID }, imageGallery);
}
I have put this line of code in my Global.asax to avoid self referencing loop:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
I'm using POSTMAN to get and post Json Objects. But when i'm trying the Post, i encounter that error.
{
"Message": "The request is invalid.",
"ModelState": {
"imageGallery": [
"Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'MobileApis.Models.ImageGallery' because the type requires a JSON object (e.g. {\"name\":\"value\"}) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON object (e.g. {\"name\":\"value\"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.\r\nPath '', line 1, position 1."
]
}
}
Here is my GET Response:
[
{
"Images": [
{
"ID": 3,
"ImageGalleryID": 1,
"Caption": "Image 1",
"Url": "http://placehold.it/350x150"
},
{
"ID": 4,
"ImageGalleryID": 1,
"Caption": "Image 2",
"Url": "http://placehold.it/350x150"
},
{
"ID": 5,
"ImageGalleryID": 1,
"Caption": "Image 3",
"Url": "http://placehold.it/350x150"
},
{
"ID": 6,
"ImageGalleryID": 1,
"Caption": "Image 4",
"Url": "http://placehold.it/350x150"
}
],
"ID": 1,
"Name": "Image Gallery 1"
}
]
I will be so happy, if you help me.

Resources