KGy SOFT

ResXDataNode Class

KGy SOFT Core Libraries Help
Represents a resource or metadata element in an XML resource (.resx) file.
See the Remarks section for an example and for the differences compared to System.Resources.ResXDataNode class.
Inheritance Hierarchy

SystemObject
  KGySoft.ResourcesResXDataNode

Namespace:  KGySoft.Resources
Assembly:  KGySoft.CoreLibraries (in KGySoft.CoreLibraries.dll) Version: 5.0.0-rc.1
Syntax

[SerializableAttribute]
public sealed class ResXDataNode : ISerializable, 
	ICloneable

The ResXDataNode type exposes the following members.

Constructors

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

  NameDescription
Public propertyAssemblyAliasValue
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 .
Public propertyComment
Gets or sets an arbitrary comment regarding this resource.
Public propertyFileRef
Gets the file reference for this resource, or , if this resource does not have a file reference.
Public propertyMimeType
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 .
Public propertyName
Gets the name of this resource.
Public propertyTypeName
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 .
Public propertyValueData
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 .
Top
Methods

  NameDescription
Public methodClone
Creates a new ResXDataNode that is a copy of the current instance.
Public methodEquals
Determines whether the specified object is equal to the current object.
(Inherited from Object.)
Public methodGetHashCode
Serves as the default hash function.
(Inherited from Object.)
Public methodGetNodeColumnPosition
Retrieves the column position of the resource in the resource file.
Public methodGetNodeLinePosition
Retrieves the line position of the resource in the resource file.
Public methodGetValue
Retrieves the object that is stored by this node.
Public methodGetType
Gets the Type of the current instance.
(Inherited from Object.)
Public methodToString
Returns a string that represents the current object.
(Overrides ObjectToString.)
Top
Extension Methods

  NameDescription
Public Extension MethodConvert(Type, CultureInfo)Overloaded.
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.)
Public Extension MethodCode exampleConvertTTarget(CultureInfo)Overloaded.
Converts an Object specified in the obj parameter to the desired TTarget.
(Defined by ObjectExtensions.)
Public Extension MethodIn (Defined by ObjectExtensions.)
Public Extension MethodTryConvert(Type, Object)Overloaded.
Tries to convert an Object specified in the obj parameter to the desired targetType.
(Defined by ObjectExtensions.)
Public Extension MethodTryConvert(Type, CultureInfo, Object)Overloaded.
Tries to convert an Object specified in the obj parameter to the desired targetType.
(Defined by ObjectExtensions.)
Public Extension MethodTryConvertTTarget(TTarget)Overloaded.
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.)
Public Extension MethodTryConvertTTarget(CultureInfo, TTarget)Overloaded.
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.)
Top
Remarks

Note Note
This class is similar to System.Resources.ResXDataNode in System.Windows.Forms.dll. See the Comparison with System.Resources.ResXDataNode section for the differences.

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 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 an existing ResXDataNode object, you can select one of the following options:

Examples

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, 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.GetValue();
                Console.WriteLine($"  Real value:  {value} ({value.GetType()})");
            }
            catch (Exception e)
            {
                Console.WriteLine($"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, System.Drawing assembly will be loaded.
//   Raw value:   Red
//   Real value:  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
// 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 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 method.

Note Note
When serialized in compatibility mode (see ResXResourceWriter.CompatibleFormat, ResXResourceSet.Save, ResXResourceManager.SaveResourceSet and ResXResourceManager.SaveAllResources), the result will be able to be parsed by the System.Resources.ResXDataNode type, too.

Incompatibility with System.Resources.ResXDataNode:

  • Name property is read-only. If you want to use a new name, instantiate a new ResXDataNode instance by the ResXDataNode(string, object) constructor and pass the new name and the original ResXDataNode as parameters.
  • There are no GetValueTypeName methods. The problem with System.Resources.ResXDataNode.GetValueTypeName methods is that they are unsafe as they may deserialize the inner object, load assemblies and can throw various unexpected exceptions. Instead, you can read the original type information stored in the .resx file by TypeName and AssemblyAliasValue properties. Based on the retrieved information you can decide whether you really want to deserialize the object by the GetValue method.
  • There is no GetValue method with AssemblyName[] argument. That overload ended up using the obsolete Assembly.LoadWithPartialName method. The weakly referenced assemblies however are handled automatically by using Reflector.ResolveType method so this overload is actually not needed.
  • The GetValue method has three parameters instead of one. But all of them are optional so if called from a regular C# code, the method is compatible with the System.Resources.ResXDataNode.GetValue(ITypeResolutionService) method.
  • There are no public constructors with Func<Type, string> arguments. In the system version these typeNameConverter parameters are used exclusively by non-public methods, which are called by the ResXResourceWriter class. But you can pass such a custom typeNameConverter to the ResXResourceWriter constructors.
  • There is no GetNodePosition method because it returned a Point structure from the System.Drawing assembly, which is not referenced by this library. Use GetNodeLinePosition and GetNodeColumnPosition methods instead.
  • The FileRef property returns the same reference during the lifetime of the ResXDataNode instance. This is alright as ResXFileRef is immutable. Unlike the system version, the FileRef property in this ResXDataNode contains exactly the same type information as the original .resx file.
  • The System.Resources.ResXDataNode.GetValue method often throws XmlException if the node contains invalid data. In contrast, this GetValue implementation may throw XmlException, TypeLoadException or NotSupportedException instead.

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 method. If a .resx file is read from an untrusted source, 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.

See Also

Reference