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.