Reporting — Safe Deserialization
- 4 minutes to read
DevExpress controls automatically detect potentially unsafe data types and block deserialization to address security-related issues. The NonTrustedTypeDeserializationException
is thrown if a reporting control attempts to load an unsafe data type.
This article describes serialization/deserialization best practices specific to DevExpress Reporting components. Review the following help section for general security considerations related to all DevExpress components: General – Safe Deserialization.
DevExpress Reporting controls deserialize the following data types automatically:
- Custom controls saved in XML/REPX.
- Complex type values for properties marked with the
XtraSerializableProperty
attribute (for example, a reference to an object). Read the following topic for additional information in this regard: How to serialize a custom property of a DevExpress control descendant. System.Object
type properties (such as theTag
property) for simple data types such as integer, float, double, decimal, bool, string, etc.
Deserialize Custom Types
A custom type must be serialized to and deserialized from a string. Use IOneTypeObjectConverter
to serialize the following custom types:
- A complex parameter value (such as IList or IDictionary).
- The control’s
Tag
property that contains a custom type (any type except primitive, string, decimal, date-time, etc.).
You should explicitly trust any bound data type your report references. If a custom type instance is a container for data types, use IObjectDataSerializer
to serialize the custom type along with its content. Read the following section for additional information: Deserialize Data Sources.
Important
Do not use the BinaryFormatter
to serialize/deserialize data. The BinaryFormatter
is not secure and is not recommended for data processing purposes. Read the following topic for additional information: Deserialization Risks in Use of BinaryFormatter and Related Types.
Example
The following example serializes/deserializes the tag property value (determines whether to display time in the parameter value of the Parameter Editor.
Implement the IOneTypeObjectConverter
interface and register the converter at application startup:
using System.Collections.Generic;
using DevExpress.Utils.Serializing.Helpers;
var app = builder.Build();
// Register a converter for the Tag property with a custom value of the ParameterEditorSettings type.
ObjectConverter.Instance.RegisterConverter(new ParameterEditorSettingsConverter());
app.Run();
sealed class ParameterEditorSettingsConverter : IOneTypeObjectConverter {
public Type Type => typeof(ParameterEditorSettings);
public object FromString(string str) {
return JsonSerializer.Deserialize<ParameterEditorSettings>(str);
}
public string ToString(object obj) {
return JsonSerializer.Serialize(obj);
}
}
Deserialize Data Sources
Data loading-related restore operations for the following data source types generate security warnings if the following data sources use untrusted types:
Use IObjectDataSerializer
to serialize custom data sources.
Example
The example below creates and registers a custom serializer for an object data source.
Implement and register a custom serializer (EmployeeListSerializer
) that implements safe serialization/deserialization of the Employee
data source type.
using System.Collections.Generic;
using DevExpress.Utils.Serializing;
var app = builder.Build();
// Allow custom data source serialization.
DevExpress.Utils.DeserializationSettings.RegisterTrustedClass(typeof(EmployeeDataSource));
// Register a custom serializer for Employee.
ObjectDataSerializer.Register<Employee>(new EmployeeListSerializer());
app.Run();
}
sealed class EmployeeListSerializer : IObjectDataSerializer {
public bool CanDeserialize(string value, string typeName) {
return typeName == typeof(List<Employee>).FullName;
}
public bool CanSerialize(object data) {
return data is List<Employee>;
}
public object Deserialize(string value, string typeName) {
if(typeName == typeof(List<Employee>).FullName)
return JsonSerializer.Deserialize<List<Employee>>(value);
throw new NotSupportedException();
}
public string Serialize(object data) {
return JsonSerializer.Serialize(data);
}
}
To allow data source serialization, explicitly trust the data source type at application startup.
var app = builder.Build();
// Allow custom data source serialization.
DevExpress.Utils.DeserializationSettings.RegisterTrustedClass(typeof(EmployeeDataSource));
app.Run();
public partial class EmployeesReport : DevExpress.XtraReports.UI.XtraReport {
public EmployeesReport() {
// ...
this.objectDataSource1.DataSource = typeof(WebEFCoreApp.Data.EmployeeDataSource);
// ...
}
}
Deserialize Report Parameters
Implement a type converter to convert custom types to/from a string to deserialize complex parameter values (for example, IList, IDictionary). The DevExpress serialization/deserialization mechanism invokes the type converter whenever it encounters a registered custom type.
Example
The example below creates a custom type converter (DictionaryConverter).
Implement the IOneTypeObjectConverter
interface and register the converter at application startup.
using DevExpress.Utils.Serializing.Helpers;
var app = builder.Build();
// Register a converter for the custom parameter of the Dictionary<string, int> type.
ObjectConverter.Instance.RegisterConverter(new DictionaryConverter());
app.Run();
sealed class DictionaryConverter : IOneTypeObjectConverter {
public Type Type => typeof(Dictionary<string, int>);
public object FromString(string str) {
return JsonSerializer.Deserialize<Dictionary<string, int>>(str);
}
public string ToString(object obj) {
return JsonSerializer.Serialize(obj);
}
}