-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handling nullable responses in NSwag-generated clients, and modernizing controller definitions #88
Comments
This need to be tested on the version 1.10. |
We've implemented and tested that and have some suggestions. Define null returnFirst of all we would suggest to not use the xml comment to define that a return value can be null, but use the [Theory]
[MemberData(nameof(NullableActions))]
public void CanBeNullAttribute_IsSet_Everywhere(NamedWrapper<MethodInfo> infoWrap)
{
MethodInfo info = infoWrap;
if (!info.ReturnParameter.CustomAttributes.Any(data => data.AttributeType.IsAssignableFrom(typeof(CanBeNullAttribute))))
{
Assert.Fail($"{infoWrap} should have the [return: CanBeNull] attribute)");
}
} where public static TheoryData<NamedWrapper<MethodInfo>> NullableActions
{
get
{
var ret = new TheoryData<NamedWrapper<MethodInfo>>();
foreach (var namedWrapper in ActionMethods
.Where(info =>
info.ReturnParameter?.CustomAttributes.Any(o => o.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute") == true)
.Select(info =>
new NamedWrapper<MethodInfo>(info, methodInfo => $"{methodInfo.DeclaringType}.{methodInfo.Name}")
))
{
ret.Add(namedWrapper);
}
return ret;
}
}
private static IEnumerable<MethodInfo> ActionMethods
{
get
{
var ret = typeof(SomeController)
.Assembly
.GetExportedTypes()
.SelectMany(type => type
.GetMethods(BindingFlags.Public | BindingFlags.Instance)
.Where(info => info.GetCustomAttributes().Any(attribute => attribute.GetType().IsAssignableTo(typeof(HttpMethodAttribute))))
);
return ret;
}
} So every Action returning a nullable object, will be checked if it has the How to handle
|
Why was this closed ? |
These modifications have the following objectives:
null
responses to be sent from controllersThe modifications apply for Yarp and all other services.
Host project modifications
Infrastructure
Add the following code in the
Infrastructure
folder. This is a model provider that will addProducesResponseTypeAttribute
instances deduced from the return value of the methods. In addition, it will also add a response type forAppException
instances, as is done explicitly today.Replace
SolutionName
with the name of your solution.Program.cs
In
Program.cs
, locate the statementservices.AddControllers()
and adjust it as follows:The
OutputFormatters
statement removes the implicit conversion from successful (200) null responses to 204 empty responses.This is needed to avoid raising a
RestException
for a 204 if a null return value is an indication of a non-existing result.The documentation is hidden in Special case formatters. The saga about the implicit conversions can be found dotnet/aspnetcore#8847. Note that the issue has been closed by Microsoft without satisfying resolution (except the workaround described here).
The other statements adds the application model provider you defined in the previous point. Don't worry about the "Transient" lifetime, it will be called only once anyway.
Sdk project modifications (optional)
In the
facade.swag
andinterface.nswag
, locate thegenerateNullableReferenceTypes
property in thecodeGenerators:openApiToCSharpClient
section and change its value totrue
.This adds
#nullable true
in the client code, and generates nullable reference types when needed.If you do this, you need to change .netstandard2.0 to .netstandard2.1 in your facade's
.csproj
file, since nullable reference types are a language feature that does not exist in .netstandard2.0.You can ommit this if you want.
Controllers specification
Using strongly typed return values and adding a cancellation token
When generating a controller you can return a strongly typed value
T
,ActionResult<T>
,Task<T>
orTask<ActionResult<T>>
. In that case, no[ProducesResponeType()]
attribute will be needed if you only report "200 Success" or raise anAppException
.You can still add
[ProducesResponeType()]
in case your method returns several status codes, and/or does not want to use a strongly typed result.If the methods of your controller are asynchronous, it is a good practice to specify a
CancellationToken
as the last parameter. The source of thecancellationToken
will beHttpContext.RequestAborted
, which will allow you to stop any long running requests.See Handling aborted requests in Asp.Net.
For example, where previously you specified a controller and method like this (irrelevant details omitted):
Now you write it like this:
The cancellation token should be passed to the business layer, but it wasn't done here.
The generated Sdk code should be exactly the same.
Returning
null
from actions, and specifying mandatory parametersIf you need to specify a method returning a nullable reference, you need to:
nullable="true"
in the response comment tag.If you need to express the mandatory presence of a parameter, use the attribute
[BindRequired]
when specifying it.This is an example of a method returning a possible
null
depending on a mandatoryreturnNull
parameter:The most important indication for nullability is not the NRT itself, but the attribute
nullable="true"
in response comment !In the generated Sdk, the return value will be an NRT (as expected), and the OpenAPI .json description will indicate that the return value is nullable.
By default, parameter binding will be optional, which will translate in a nullable data type in the generated SDK, and a default value in the called method (
false
in thebool
case). If you want to make the parameter mandatory,[BindRequired]
needs to be specified.The text was updated successfully, but these errors were encountered: