It seems the current version does not render swagger
/definitions/{entity}/required array
As a result all the entity/object fields generated based on swagger are nullable.
To me this is this the single most painful drawback.
Can you please create a sample project that reproduces your issue...
I'm running the latest version without errors.
It is not an error, I see it as a lack of feature. I investigate and might be able to produce pull request.
When you say "current version does not render swagger" that sounds like an error ...
But if you have a PR in the works please add some more details and send it, thanks
Ok, I see where the problem is. Object definitions are carried by JsonObjectContract (CreateObjectSchema method) and object properties get listed as required only when they are marked with [Required] attribute.
As a result class test { int MyId; } and class test { int? MyId; } produce the same swagger definitions.
I am not certain what the right solution should be but I know that, for instance, EF Core generated objects (DB first) do not contain properties marked with [Required] attributes. They simply make simple types nullable or not - when the property is required. It goes without saying that adding [Required] attributes everywhere every time objects are (re)populated is not a desired solution.
How is this addressed in the new .Net Core version?
I'm still not clear what your issue or feature is ...
Can you create a sample project that shows this ?
In short: class test { public int MyId; } and class test { public int? MyId; } produce the same swagger definitions.
I believe they should not.
Btw, what is the purpose of WorkItem.InProgress attribute? Is it used for some thread safety?
Here is an example using your classes:
https://github.com/heldersepu/SwashbuckleTest/commit/ef912528267519edbf9f4203915a11d12387c329
Those classes are parameters in some actions
...and Yes the definitions are the same:
"test1":{
"type": "object",
"properties":{
"MyId":{
"format": "int32",
"type": "integer",
"example": 123
},
}
},
"test2":{
"type": "object",
"properties":{
"MyId":{
"format": "int32",
"type": "integer",
"example": 123
},
}
},
But a nullable value should have no impact on a consumer making a post request
http://swashbuckletest.azurewebsites.net/swagger/ui/index#!/RoutePrefix/RoutePrefix_PostTest1
We can do posts on both controllers with a value:
{
"data": "b4ecbbea-6314-4347-bbba-b7422f6e3f9e"
}
The one with the nullable value will give you a null the other 0
But that is not because swagger that is the WebApi
Thank you for the explanation. I guess my needs are just somewhat special. I have edmx generated objects I use as DTOs - so no [Required] attributes. Based on rendered swagger I generate client side DTOs and I need them closely reassemble those on the server side - particularly when it comes to nullability.
I am going to modify the code (JsonProperty.IsRequired extension) so it returns true only for non-nullable value types and I should be good to go.
WebApi are supposed to be simple, I can't really picture what your are trying to accomplish without a sample project, and client side (assuming JavaScript) all fields can have the value null or undefined.
Since this is not a Swashbuckle issue, can you please close this issue.
Just in case someone has a similar needs here is the solution: modify JsonPropertyExtensions.IsRequired extension method as follows:
public static bool IsRequired(this JsonProperty jsonProperty)
{
Type type = jsonProperty.PropertyType;
return jsonProperty.HasAttribute<RequiredAttribute>() || (type.IsValueType && !(type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>))));
}
@heldersepu The issue is that the ASP.NET model binder assumes that because value types cannot be null, they are required. If you make a value type nullable, then it is optional (unless it has a Required attribute, but I dunno why you would do that). Reference types can be null so are by default optional without a Required attribute.
It seems @tdjastrzebski's solution requires modifying swashbuckle which I would like to avoid, so I will see what I can do with an ISchemaFilter.
@redwyre Should you find a better response to this not uncommon challenge, please post it.
In my view the problem is that by default the tool assumes nullable value types are required, unless they are marked with [Required] attribute.
This is what I came up with:
public class ValueTypesRequired : ISchemaFilter
{
public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
// this is null for things like dictionaries which get converted to a generic object
if (schema.properties != null)
{
var valueTypeProps = type.GetProperties()
.Where(p => p.PropertyType.IsValueType);
foreach (var prop in valueTypeProps)
{
if (schema.properties.TryGetValue(prop.Name, out Schema propSchema))
{
if (schema.required == null)
{
schema.required = new List<string>();
}
if (!schema.required.Contains(prop.Name))
{
schema.required.Add(prop.Name);
}
}
}
}
}
}
Not sure if there are any edge cases that aren't handled, but it seems to work.
Thanks @redwyre for this code. For anyone wondering how to apply it, just open SwaggerConfig.cs and add:
c.SchemaFilter<ValueTypesRequired>();
in middle of that commented GlobalConfiguration.Configuration.EnableSwagger(c=> { /* ADD HERE */ }); call.
Most helpful comment
This is what I came up with:
Not sure if there are any edge cases that aren't handled, but it seems to work.