2026-03: DataResult ctor
The DataResult(object result, string message = "") constructor is deprecated and will be removed in a future version.
What is changing
Previously, DataResult had a single public constructor:
// DEPRECATED — do not use in new code
return new DataResult(myObject, "Operation succeeded");
This constructor had two problems:
- It used Newtonsoft.Json to serialize the response, which is being phased out in favour of
System.Text.Jsonacross the framework. - It always wrapped the response in the Jetveo command envelope (
{ "success", "message", "result" }), giving callers no way to return plain JSON or other formats.
The constructor is replaced by a set of static factory methods that give explicit control over serialization format and response shape.
Migration
Closest equivalent — DataResult.CommandJson
If you were relying on the envelope format ({ "success", "message", "result" }), replace the old constructor with DataResult.CommandJson. The response shape is identical; the only difference is that serialization now uses System.Text.Json.
// Before
return new DataResult(myObject, "Operation succeeded");
// After
return DataResult.CommandJson(myObject, message: "Operation succeeded");
CommandJson also supports success: false for error responses and optional JsonSerializerOptions:
return DataResult.CommandJson(errorPayload, success: false, message: "Validation failed");
return DataResult.CommandJson(myObject, serializationOptions: new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
Polymorphism note: If your result type uses inheritance (e.g. a
List<Animal>that containsDogorCatinstances),System.Text.Jsonwill only serialize the properties of the declared element type. Newtonsoft.Json serialized the full runtime type automatically. See the Appendix: Polymorphism below before migrating.
Full API reference
DataResult.CommandJson — enveloped JSON (Jetveo command protocol)
Returns a JSON response wrapped in the standard Jetveo command envelope:
{ "success": true, "message": "...", "result": { ... } }
DataResult.CommandJson(object data, bool success = true, string message = "", JsonSerializerOptions serializationOptions = null)
HTTP status code follows the success flag: 200 OK for true, 400 Bad Request for false. Serialized with System.Text.Json.
DataResult.Json — plain JSON
Returns the data serialized as JSON with no envelope. Two overloads:
// Serialize a CLR object with System.Text.Json
DataResult.Json(object data, JsonSerializerOptions serializationOptions = null)
// Pass a pre-serialized JSON string through as-is (no re-serialization)
DataResult.Json(string json)
Use Json(object) when you have a CLR object and want a clean JSON response without the command envelope. Use Json(string) when you have already-serialized JSON — for example, when proxying a response from an external service.
return DataResult.Json(new { items = list, total = list.Count });
return DataResult.Json(rawJsonFromExternalApi);
DataResult.Xml — XML
Serializes the object using System.Xml.Serialization.XmlSerializer. Content-Type is application/xml; charset=UTF-8.
DataResult.Xml(object data, XmlWriterSettings settings = null)
return DataResult.Xml(myDto);
return DataResult.Xml(myDto, new XmlWriterSettings { Indent = true });
DataResult.Text — plain text or other text formats
Returns a string response with a configurable MIME type. Defaults to text/plain.
DataResult.Text(string content, string mimeType = "text/plain")
return DataResult.Text("Hello, world!");
return DataResult.Text("<h1>Hello</h1>", mimeType: "text/html");
return DataResult.Text(csvContent, mimeType: "text/csv");
DataResult.Data — raw binary
Returns raw bytes with a configurable MIME type. Providing a fileName adds a Content-Disposition: attachment header, which triggers a file download in browsers.
DataResult.Data(byte[] data, string mimeType, string fileName = null)
return DataResult.Data(pdfBytes, mimeType: "application/pdf", fileName: "report.pdf");
return DataResult.Data(imageBytes, mimeType: "image/png");
Summary
| Old usage | New equivalent |
|---|---|
new DataResult(obj) | DataResult.CommandJson(obj) |
new DataResult(obj, "msg") | DataResult.CommandJson(obj, message: "msg") |
| Plain JSON response (no envelope) | DataResult.Json(obj) |
| Pass-through JSON string | DataResult.Json(jsonString) |
| XML response | DataResult.Xml(obj) |
| Plain text / CSV / HTML | DataResult.Text(content, mimeType) |
| Binary file download | DataResult.Data(bytes, mimeType, fileName) |
Appendix: Polymorphism
System.Text.Json and Newtonsoft.Json handle inheritance differently. This is the most common source of silent regressions when migrating.
The problem
Newtonsoft.Json serializes the runtime type of every value, including collection elements. System.Text.Json serializes the declared type. When the two differ — most commonly in a List<BaseType> that contains derived instances — System.Text.Json will silently omit the derived properties.
class Animal { public string Name { get; set; } }
class Dog : Animal { public string Breed { get; set; } }
List<Animal> animals = new() { new Dog { Name = "Rex", Breed = "Labrador" } };
// Legacy (Newtonsoft): { "result": [{ "Name": "Rex", "Breed": "Labrador" }] } ← Breed included
// DataResult.CommandJson (STJ): { "result": [{ "Name": "Rex" }] } ← Breed silently dropped
If you are directly returning a concrete type or an object, both serializers behave the same — no change is needed.
Option 1 — [JsonDerivedType] (recommended)
Annotate the base class to tell STJ which subtypes exist. No other code changes are required.
using System.Text.Json.Serialization;
[JsonDerivedType(typeof(Dog))]
[JsonDerivedType(typeof(Cat))]
class Animal { public string Name { get; set; } }
class Dog : Animal { public string Breed { get; set; } }
class Cat : Animal { public bool IsIndoor { get; set; } }
With this in place, DataResult.CommandJson(animals) will include Breed and IsIndoor correctly.
By default [JsonDerivedType] does not add a type discriminator to the JSON output, so the response shape stays identical to what Newtonsoft produced. If you need clients to deserialize back to the correct subtype, add a discriminator:
[JsonDerivedType(typeof(Dog), typeDiscriminator: "dog")]
[JsonDerivedType(typeof(Cat), typeDiscriminator: "cat")]
class Animal { ... }
Option 2 — Return a concrete list type
If you cannot annotate the base class (e.g. it is defined in a library you do not control), return a concrete list that STJ can inspect at the element level:
// Instead of List<Animal>:
var dogs = animals.OfType<Dog>().ToList(); // List<Dog> — STJ sees Dog
return DataResult.CommandJson(dogs);
// Or cast the whole list to object — STJ uses the runtime type for object-typed values:
return DataResult.CommandJson((object)animals); // runtime type List<Animal> — same STJ limitation
Note: casting to object does not help here because the runtime element type is still Animal. Return List<Dog> directly, or use a wrapper DTO.
Option 3 — Custom JsonSerializerOptions with a polymorphic converter
For complex hierarchies where you need full control, pass a converter through serializationOptions:
var options = new JsonSerializerOptions();
options.Converters.Add(new PolymorphicAnimalConverter());
return DataResult.CommandJson(animals, serializationOptions: options);
This is the most flexible but also the most code to maintain. Prefer [JsonDerivedType] where possible.