Why does the API client (IJsonServiceClient) return a nullable response?
The GetAsync Method should return either the response or an exception but not null.
What do i miss here?
The client interfaces have existed since the dawn of ServiceStack, which have many implementors, long before #nullable was added to C#. This interface doesn’t change the behavior of the concrete JsonApiClient that implements.
Is there a reason why you’re using IJsonServiceClient
instead of the concrete JsonApiClient
?
We use the Interface for decoupeling reasons, to avoid working directly with the Implementation. The concrete Implementation which gets injected is the JsonApiClient
. But even if i use the concrete Implementation directly, the IDE still suggests that the response could be nullable.
My Question here is, wouldn’t it make sense to annotate the function, so nullable response is not possible? Either a response is given or an exception is thrown, a nullable response is not an option in cases where the Request has a
IReturn<TResponse>
defined.Or Is there a way how i can generate the dto’s with #nullable enable?
The JsonApiClient is already annotated with #nullable enable
and all the APIs on the concrete JsonApiClient
don’t return nullable responses:
Which is what I’m seeing:
Not sure why your IDE is reporting it differently. Does your ServiceModel.csproj have nullable enabled?
In the meantime I’ve just added #nullable enable
to all client interfaces (and all types in top-level ServiceStack.Interfaces project) in this commit. With this change even the IServiceClient
interfaces report non nullable responses:
This change is available from v8.8.1+ which is now available in pre-release packages
FYI as JsonApiClient
uses HttpClient you don’t want to be using it with using var
or calling Dispose()
on it manually. It’s instead recommended to use the ASP .NET Core’s IHttpClientFactory Registration, e.g:
builder.Services.AddJsonApiClient(builder.Configuration["BaseUrl"]);
Which just registers JsonApiClient as a Typed Client:
services.AddHttpClient<JsonApiClient>(client => client.BaseAddress = new Uri(baseUrl));
Where you’ll be able to inject JsonApiClient
as a dependency into your C# client Apps.
var result = await jsonClient.GetAsync(new GetCantonRequest
{
CantonId = cantonId
});
The problem is that the request GetCantonRequest comes from the generated dto file and even though we enable nullable in the csproj. Rider still thinks it could return nullable if we do not define the type parameter explicitly. The issue is only resolved when we add the #nullable enable to the generated dto file. So my question is, is there a way to generate the dto’s with #nullable enable set?
I don’t see how nullable reference types on DTOs are going to have an effect on the return signature of an instance type.
The screenshots above are from Rider using DTOs in the ServiceModel.csproj with only <Nullable>enable</Nullable>
(i.e. without #nullable enable
on any file).
The header comments should remain at the top of the generated DTOs fails so they’re recognized by tools that update them. You can generate code below the using declarations with:
CSharpGenerator.InsertCodeFilter = (type, code) => "#nullable enable\n";
I’ve just tried this in Rider and it appears that it still has an effect of enabling nullable reference type checks.
This solutions works. Thank you.
Now we have one last issue. We have a server which runs on .Net v4.8. We fetch dto’s from this server with AddNullableAnnotations config set to true in the dto file. The dto’s generated gives us properties which have reference types marked as null even though they cannot be null from business logic perspective. How can we mark these properties, so that servicestack dto generation does not add nullable annotation to these?
Code on Server (.Net 4.8)
public class GetMacroregionCoordinateResponse
{
public MasterDataCoordinateModel Entity { get; set; }
}
dto’s generated
[GeneratedCode("AddServiceStackReference", "8.72")]
public partial class GetMacroregionCoordinateResponse
{
public virtual MasterDataCoordinateModel? Entity { get; set; }
}
We do not want MasterDataCoordinateModel marked as nullable in the dto.
The default behavior should be to not generate DTOs with nullable reference types. You would need to opt into generating DTOs will nullable reference types by uncommenting AddNullableAnnotations:
/* Options:
Date: 2025-06-04 16:51:08
Version: 8.81
....
AddNullableAnnotations: True
If your server DTOs does not have #nullable enable
enabled and you would still like to generate DTOs with nullable notations you can mark that a Reference Type is required by using the [Required]
attribute, e.g:
public class GetMacroregionCoordinateResponse
{
[Required]
public MasterDataCoordinateModel Entity { get; set; }
}
Wouldn’t it make sense to add required
to the property in the generated dto, when the Attribute [Required] is set on the Server side for example her the result should look like this:
public required MasterDataCoordinateModel Entity { get; set; }
Currently i have solved this with the PropertyTypeFilter
CSharpGenerator.PropertyTypeFilter = (generator, type, property) => $"{(property.IsRequired ?? false ? "required " : string.Empty)}{generator.GetPropertyType(property)}";
But maybe this would make sense to support in the CSharpGenerator directly.
If you can use the required
modifier, you can enable nullable annotations. The [Required]
attribute is when that’s not available.
Let’s say i have a .Net Framework v4.8 API, which defines it’s dto like this:
public class GetMacroregionCoordinateResponse
{
[Required]
public MasterDataCoordinateModel Entity { get; set; }
}
and i have a .Net Core v8 Client which uses the API and wants to generate the dto’s with nullable annotations enabled. The generated dto looks like this:
#nullable enable
[GeneratedCode("AddServiceStackReference", "8.60")]
public partial class GetMacroregionCoordinateResponse
{
[Required]
public virtual MasterDataCoordinateModel Entity { get; set; }
}
This will result in this Error:
Error CS8618 : Non-nullable property 'Entity' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
That’s why it would be nice to have the ability to set the required
on the property. Currently i’ve solve the issue with this line:
CSharpGenerator.PropertyTypeFilter = (generator, type, property) => $"{(property.IsRequired ?? false ? "required " : string.Empty)}{generator.GetPropertyType(property)}";
It isn’t a compiler error by default, you would have to have reporting warnings as errors configured, which I wouldn’t for serializable types or generated code you don’t control.