System.Text.Json ServiceStack APIs
In continuing our focus to enable ServiceStack to become a deeply integrated part of .NET 8 Application's, ServiceStack latest .NET 8 templates now default to using standardized ASP.NET Core features wherever possible, including:
- ASP.NET Core Identity Auth
- ASP.NET Core IOC
- Endpoint Routing
- Swashbuckle for Open API v3 and Swagger UI
- System.Text.Json APIs
This reduces friction for integrating ServiceStack into existing .NET 8 Apps, encourages greater knowledge and reuse and simplifies .NET development as developers have a reduced number of concepts to learn, fewer technology implementations to configure and maintain that are now applied across their entire .NET App.
The last integration piece supported was utilizing System.Text.Json - the default high-performance async JSON serializer used in .NET Applications, can now be used by ServiceStack APIs to serialize and deserialize its JSON API Responses that's enabled by default when using Endpoint Routing.
This integrates ServiceStack APIs more than ever where just like Minimal APIs and Web API, uses ASP.NET Core's IOC to resolve dependencies, uses Endpoint Routing to Execute APIs that's secured with ASP.NET Core Identity Auth then uses System.Text.Json to deserialize and serialize its JSON payloads.
Enabled by Default when using Endpoint Routing​
app.UseServiceStack(new AppHost(), options => {
options.MapEndpoints();
});
Enhanced Configuration​
ServiceStack uses a custom JsonSerializerOptions
to improve compatibility with existing ServiceStack DTOs and
ServiceStack's rich ecosystem of generic Add ServiceStack Reference
Service Clients, which is configured to:
- Not serialize
null
properties - Supports Case Insensitive Properties
- Uses
CamelCaseNamingPolicy
for property names - Serializes
TimeSpan
andTimeOnly
Data Types with XML Schema Time format - Supports
[DataContract]
annotations - Supports Custom Enum Serialization
Benefits all Add ServiceStack Reference Languages​
This compatibility immediately benefits all of ServiceStack's Add ServiceStack Reference native typed integrations for 11 programming languages which all utilize ServiceStack's JSON API endpoints - now serialized with System.Text.Json
Support for DataContract Annotations​
Support for .NET's DataContract
serialization attributes was added using a custom TypeInfoResolver
, specifically it supports:
[DataContract]
- When annotated, only[DataMember]
properties are serialized[DataMember]
- Specify a custom Name or Order of properties[IgnoreDataMember]
- Ignore properties from serialization[EnumMember]
- Specify a custom value for Enum values
Custom Enum Serialization​
Below is a good demonstration of the custom Enum serialization support which matches ServiceStack.Text's behavior:
public enum EnumType { Value1, Value2, Value3 }
[Flags]
public enum EnumTypeFlags { Value1, Value2, Value3 }
public enum EnumStyleMembers
{
[EnumMember(Value = "lower")]
Lower,
[EnumMember(Value = "UPPER")]
Upper,
}
return new EnumExamples {
EnumProp = EnumType.Value2, // String value by default
EnumFlags = EnumTypeFlags.Value2 | EnumTypeFlags.Value3, // [Flags] as int
EnumStyleMembers = EnumStyleMembers.Upper, // Serializes [EnumMember] value
NullableEnumProp = null, // Ignores nullable enums
};
Which serializes to:
{
"enumProp": "Value2",
"enumFlags": 3,
"enumStyleMembers": "UPPER"
}
Custom Configuration​
You can further customize the JsonSerializerOptions
used by ServiceStack by using ConfigureJsonOptions()
to add
any customizations that you can optionally apply to ASP.NET Core's JSON APIs and MVC with:
builder.Services.ConfigureJsonOptions(options => {
options.PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower;
})
.ApplyToApiJsonOptions() // Apply to ASP.NET Core's JSON APIs
.ApplyToMvcJsonOptions(); // Apply to MVC
Control over when and where System.Text.Json is used​
Whilst System.Text.Json
is highly efficient, it's also very strict in the inputs it accepts where you may want to
revert back to using ServiceStack's JSON Serializer for specific APIs, especially when you need to support external
clients that can't be updated.
This can done by annotating Request DTOs with [SystemJson]
attribute, e.g: you can limit to only use System.Text.Json
for an APIs Response with:
[SystemJson(UseSystemJson.Response)]
public class CreateUser : IReturn<IdResponse>
{
//...
}
Or limit to only use System.Text.Json
for an APIs Request with:
[SystemJson(UseSystemJson.Request)]
public class CreateUser : IReturn<IdResponse>
{
//...
}
Or not use System.Text.Json
at all for an API with:
[SystemJson(UseSystemJson.Never)]
public class CreateUser : IReturn<IdResponse>
{
//...
}
JsonApiClient Support​
When Endpoints Routing is configured, the JsonApiClient
will also be configured to utilize the same System.Text.Json
options to send and receive its JSON API Requests which also respects the [SystemJson]
specified behavior.
Clients external to the .NET App can be configured to use System.Text.Json
with:
ClientConfig.UseSystemJson = UseSystemJson.Always;
Whilst any custom configuration can be applied to its JsonSerializerOptions
with:
TextConfig.ConfigureSystemJsonOptions(options => {
options.PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower;
});
Scoped JSON Configuration​
We've also added partial support for Customized JSON Responses for the following customization options:
Name | Alias |
---|---|
EmitCamelCaseNames | eccn |
EmitLowercaseUnderscoreNames | elun |
EmitPascalCaseNames | epcn |
ExcludeDefaultValues | edv |
IncludeNullValues | inv |
Indent | pp |
These can be applied to the JSON Response by returning a decorated HttpResult
with a custom ResultScope
, e.g:
return new HttpResult(responseDto) {
ResultScope = () =>
JsConfig.With(new() { IncludeNullValues = true, ExcludeDefaultValues = true })
};
They can also be requested by API consumers by adding a ?jsconfig
query string with the desired option or its alias, e.g:
/api/MyRequest?jsconfig=EmitLowercaseUnderscoreNames,ExcludeDefaultValues
/api/MyRequest?jsconfig=eccn,edv
SystemJsonCompatible​
Another configuration automatically applied when System.Text.Json
is enabled is:
JsConfig.SystemJsonCompatible = true;
Which is being used to make ServiceStack's JSON Serializer more compatible with System.Text.Json
output so it's easier
to switch between the two with minimal effort and incompatibility. Currently this is only used to override
DateTime
and DateTimeOffset
behavior which uses System.Text.Json
for its Serialization/Deserialization.