Skip to main content

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.Json across 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 contains Dog or Cat instances), System.Text.Json will 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 usageNew 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 stringDataResult.Json(jsonString)
XML responseDataResult.Xml(obj)
Plain text / CSV / HTMLDataResult.Text(content, mimeType)
Binary file downloadDataResult.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.

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.