ResXDataNode Class

Represents a resource or metadata element in an XML resource (.resx) file.

Definition

Namespace: KGySoft.Resources
Assembly: KGySoft.CoreLibraries (in KGySoft.CoreLibraries.dll) Version: 7.0.0-rc.1
C#
[SerializableAttribute]
public sealed class ResXDataNode : ISerializable, 
	ICloneable
Inheritance
Object    ResXDataNode
Implements
ICloneable, ISerializable

Remarks

The ResXDataNode class supports the representation of rich data types within a resource file. It can support the storage of any object in a resource file.

You can create a ResXDataNode object by calling one of its overloaded class constructors. You can then add the resource item or element to a resource file by one of the following options:

  Note

If you call any of the SetObject methods of the list above by any Object, then a ResXDataNode instance will be implicitly created. A ResXDataNode instance should be explicitly created only if you want to set the Comment property.

To retrieve a ResXDataNode object from a resource you have the following options:

Example

The following example shows how to retrieve ResXDataNode instances from the IDictionaryEnumerator returned by ResXResourceReader.GetEnumerator and ResXResourceReader.GetMetadataEnumerator methods. For example, you can check the type information before deserialization if the .resx file is from an untrusted source.
C#
using System;
using System.Collections;
using System.IO;

using KGySoft.Resources;

public class Example
{
    private const string resx = @"<?xml version='1.0' encoding='utf-8'?>
<root>
  <data name='string'>
    <value>Test string</value>
    <comment>Default data type is string.</comment>
  </data>

  <metadata name='meta string'>
    <value>Meta String</value>
  </metadata>

  <data name='int' type='System.Int32'>
    <value>42</value>
  </data>

  <assembly alias='CustomAlias' name='System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' />

  <data name='color' type='System.Drawing.Color, CustomAlias'>
    <value>Red</value>
    <comment>When this entry is deserialized in an unsafe way, System.Drawing assembly will be loaded.</comment>
  </data>

  <data name='bytes' type='System.Byte[]'>
    <value>VGVzdCBieXRlcw==</value>
  </data>

  <data name='dangerous' mimetype='application/x-microsoft.net.object.binary.base64'>
    <value>YmluYXJ5</value>
    <comment>BinaryFormatter will throw an exception for this invalid content.</comment>
  </data>

</root>";

    public static void Main()
    {
        // In SafeMode the enumerator values will be ResXDataNode instances instead of deserialized objects
        var reader = new ResXResourceReader(new StringReader(resx)) { SafeMode = true };

        Console.WriteLine("____Resources in .resx:____");
        Dump(reader.GetEnumerator());

        Console.WriteLine("____Metadata in .resx:____");
        Dump(reader.GetMetadataEnumerator());
    }

    private static void Dump(IDictionaryEnumerator enumerator)
    {
        while (enumerator.MoveNext())
        {
            var node = (ResXDataNode)enumerator.Value;
            Console.WriteLine($"Name: {node.Name}");
            Console.WriteLine($"  Type:        {node.TypeName}");
            Console.WriteLine($"  Alias value: {node.AssemblyAliasValue}");
            Console.WriteLine($"  MIME type:   {node.MimeType}");
            Console.WriteLine($"  Comment:     {node.Comment}");
            Console.WriteLine($"  Raw value:   {node.ValueData}");
            try
            {
                var value = node.GetValueSafe();
                Console.WriteLine($"  Real value:  {value} ({value.GetType()})");
            }
            catch (Exception e)
            {
                Console.WriteLine($"  Safe deserialization of the node thrown an exception: {e.Message}");
                try
                {
                    var value = node.GetValue();
                    Console.WriteLine($"  Real value (unsafe):  {value} ({value.GetType()})");
                }
                catch (Exception)
                {
                    Console.WriteLine($"  Unsafe deserialization of the node thrown an exception: {e.Message}");
                }
            }
            Console.WriteLine();
        }
    }
}

// The example displays the following output:
//  ____Resources in .resx:____
// Name: string
//   Type:
//   Alias value:
//   MIME type:
//   Comment:     Default data type is string.
//   Raw value:   Test string
//   Real value:  Test string (System.String)
// 
// Name: int
//   Type:        System.Int32
//   Alias value:
//   MIME type:
//   Comment:
//   Raw value:   42
//   Real value:  42 (System.Int32)
// 
// Name: color
//   Type:        System.Drawing.Color, CustomAlias
//   Alias value: System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
//   MIME type:
//   Comment:     When this entry is deserialized in an unsafe way, System.Drawing assembly will be loaded.
//   Raw value:   Red
//   Safe deserialization of the node thrown an exception: Type "System.Drawing.Color, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" in the data at line 18, position 4 cannot be resolved.
// You may try to preload its assembly before deserialization or use the unsafe GetValue if the resource is from a trusted source.
//   Real value (unsafe):  Color[Red] (System.Drawing.Color)
// 
// Name: bytes
//  Type:        System.Byte[]
//  Alias value:
//   MIME type:
//   Comment:
//   Raw value:   VGVzdCBieXRlcw==
//   Real value:  System.Byte[] (System.Byte[])
// 
// Name: dangerous
//   Type:
//   Alias value:
//   MIME type:   application/x-microsoft.net.object.binary.base64
//   Comment:     BinaryFormatter will throw an exception for this invalid content.
//   Raw value:   YmluYXJ5
//   Safe deserialization of the node thrown an exception: End of Stream encountered before parsing was completed.
//   Unsafe deserialization of the node thrown an exception: End of Stream encountered before parsing was completed.
// 
// ____Metadata in .resx:____
// Name: meta string
//   Type:
//   Alias value:
//   MIME type:
//   Comment:
//   Raw value:   Meta String
//   Real value:  Meta String (System.String)

Comparison with System.Resources.ResXDataNode 

If instantiated from a System.Resources.ResXDataNode or System.Resources.ResXFileRef instance, an internal conversion into KGySoft.Resources.ResXDataNode and KGySoft.Resources.ResXFileRef automatically occurs.

  Note

The compatibility with System.Resources.ResXDataNode is provided without any reference to System.Windows.Forms.dll, where that type is located.

Unlike System.Resources.ResXDataNode, this ResXDataNode implementation really preserves the original information stored in the .resx file. No deserialization, assembly loading and type resolving occurs until a deserialization is explicitly requested by calling the GetValue or GetValueSafe methods.

Incompatibility with System.Resources.ResXDataNode:

New features and improvements compared to System.Resources.ResXDataNode:

  • Preserving original type information – The originally stored type information, MIME type and the current assembly alias are preserved (see TypeName, MimeType and AssemblyAliasValue properties). The system version may replace type information with assembly qualified names when the .resx file is parsed. If the assembly qualified name is really needed, you can get it after explicit deserialization by calling GetType().AssemblyQualifiedName on the Object returned by the GetValue method.
  • Raw content – You can use the ValueData property to read the original raw String content stored in the .resx file for this element.
  • Advanced string representation – The ToString method displays the string representation (either of the deserialized object if already cached, or the raw content) so can be used easily in a format argument and provides more debugging information.
  • Security – No deserialization, assembly loading and type resolving occurs until a deserialization is explicitly requested by calling the GetValue or GetValueSafe methods. If you use the GetValueSafe method, then it is guaranteed that no new assembly is loaded during the deserialization, even if the resource was serialized by BinaryFormatter. Additionally, you can check the TypeName, MimeType and AssemblyAliasValue properties to get information about the type before obtaining the object. You can even check the raw string content by the ValueData property.
  • Performance – As there is no deserialization and assembly/type resolving during parsing a .resx file by the ResXResourceReader class, the parsing is much faster. This is true even if ResXResourceReader.SafeMode is , because there are always ResXDataNode instances stored internally and deserialization occurs only when a resource is actually accessed.
  • Support of non-serializable types – When serializing an object, the System.Resources.ResXDataNode type throws an InvalidOperationException for non-serializable types. This implementation can serialize also such types even if compatibility mode is used (see ResXResourceWriter.CompatibleFormat property and the ResXResourceSet.Save methods). In compatibility mode this is achieved by wrapping the non-serializable types into an AnyObjectSerializerWrapper instance so the BinaryFormatter will able to handle them, too.
  • Support of generics – This ResXDataNode class uses a special SerializationBinder implementation, which supports generic types correctly.

Constructors

ResXDataNode(String, Object) Initializes a new instance of the ResXDataNode class.
ResXDataNode(String, ResXFileRef, String) Initializes a new instance of the ResXDataNode class with a reference to a resource file.

Properties

AssemblyAliasValue Gets the assembly name defined in the source .resx file if TypeName contains an assembly alias name, or , if TypeName contains the assembly qualified name. If the resource does not contain the .resx information (that is, if the ResXDataNode was created from an object or the raw .resx data was removed on a GetValue call), then this property returns .
Comment Gets or sets an arbitrary comment regarding this resource.
FileRef Gets the file reference for this resource, or , if this resource does not have a file reference.
MimeType Gets the MIME type as it is stored in the .resx file for this resource, or , if the mimetype attribute was not defined in the .resx file. If the resource does not contain the .resx information (that is, if the ResXDataNode was created from an object or the raw .resx data was removed on a GetValue call), then this property returns .
Name Gets the name of this resource.
TypeName Gets the type information as String as it is stored in the source .resx file. It can be either an assembly qualified name, or a type name with or without an assembly alias name. If AssemblyAliasValue is not , this property value contains an assembly alias name. The property returns , if the type attribute is not defined in the .resx file. If the resource does not contain the .resx information (that is, if the ResXDataNode was created from an object or the raw .resx data was removed on a GetValue call), then this property returns .
ValueData Gets the raw value data as String as it was stored in the source .resx file. If the resource does not contain the .resx information (that is, if the ResXDataNode was created from an object or the raw .resx data was removed on a GetValue call), then this property returns .

Methods

Clone Creates a new ResXDataNode that is a copy of the current instance.
GetNodeColumnPosition Retrieves the column position of the resource in the resource file.
GetNodeLinePosition Retrieves the line position of the resource in the resource file.
GetValue Retrieves the object that is stored by this node.
GetValueSafe Retrieves the object that is stored by this node, not allowing loading assemblies during the possible deserialization.
ToString Returns a string that represents the current object.
(Overrides ObjectToString)

Extension Methods

Convert Converts an Object specified in the obj parameter to the desired targetType.
See the Examples section of the generic ConvertTTarget(Object, CultureInfo) overload for an example.
(Defined by ObjectExtensions)
ConvertTTarget Converts an Object specified in the obj parameter to the desired TTarget.
(Defined by ObjectExtensions)
In Gets whether item is among the elements of set.
See the Examples section of the generic InT(T, T) overload for an example.
(Defined by ObjectExtensions)
TryConvert Tries to convert an Object specified in the obj parameter to the desired targetType.
See the Examples section of the ConvertTTarget(Object, CultureInfo) method for a related example.
(Defined by ObjectExtensions)
TryConvert Tries to convert an Object specified in the obj parameter to the desired targetType.
See the Examples section of the ConvertTTarget(Object, CultureInfo) method for a related example.
(Defined by ObjectExtensions)
TryConvertTTarget Tries to convert an Object specified in the obj parameter to the desired TTarget.
See the Examples section of the ConvertTTarget(Object, CultureInfo) method for a related example.
(Defined by ObjectExtensions)
TryConvertTTarget Tries to convert an Object specified in the obj parameter to the desired TTarget.
See the Examples section of the ConvertTTarget(Object, CultureInfo) method for a related example.
(Defined by ObjectExtensions)

See Also