YamlDotNet icon indicating copy to clipboard operation
YamlDotNet copied to clipboard

AnchorNotFoundException: Alias $shared-api-worker-env cannot precede anchor declaration

Open iccfish opened this issue 8 months ago • 1 comments

I'm trying to deserialize docker-compose.yaml from dify project.

Consider follow classes:

class DockerComposeFile
{
	[YamlMember(Alias = "x-shared-env")]
	public Dictionary<string, string> XSharedEnv { get; set; }
	
	public Dictionary<string, ServiceDefinition> Services { get; set; }
}

class ServiceDefinition
{
	public string Image { get; set; }
	public Dictionary<string, string> Environment { get; set; }
}

and following yaml:

x-shared-env: &shared-api-worker-env
  CONSOLE_API_URL: ${CONSOLE_API_URL:-}
  CONSOLE_WEB_URL: ${CONSOLE_WEB_URL:-}
  SERVICE_API_URL: ${SERVICE_API_URL:-}

services:
  api:
    image: langgenius/dify-api:0.15.2
    restart: always
    environment:
      # Use the shared environment variables.
      <<: *shared-api-worker-env
      # Startup mode, 'api' starts the API server.
      MODE: api
    depends_on:
      - db
    volumes:
      - ./volumes/app/storage:/app/api/storage
    networks:
      - default

Using following code to deserialize:

	var deserializer = new DeserializerBuilder()
				.WithNamingConvention(UnderscoredNamingConvention.Instance)
				.WithCaseInsensitivePropertyMatching()
				.IgnoreUnmatchedProperties()
				.Build();

	var obj = deserializer.Deserialize<DockerComposeFile>(File.ReadAllText(@"docker-compose.yaml"));
	obj.Dump();

Exception was thrown:

AnchorNotFoundException: Alias $shared-api-worker-env cannot precede anchor declaration
at YamlDotNet.Serialization.ValueDeserializers.AliasValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.<>c__DisplayClass6_0.<DeserializeValue>b__1(IParser r, Type t)
   at YamlDotNet.Serialization.NodeDeserializers.DictionaryDeserializer.Deserialize(Type tKey, Type tValue, IParser parser, Func`3 nestedObjectDeserializer, IDictionary result, ObjectDeserializer rootDeserializer)
   at YamlDotNet.Serialization.NodeDeserializers.DictionaryNodeDeserializer.Deserialize(IParser parser, Type expectedType, Func`3 nestedObjectDeserializer, Object& value, ObjectDeserializer rootDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.AliasValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.<>c__DisplayClass6_0.<DeserializeValue>b__1(IParser r, Type t)
   at YamlDotNet.Serialization.NodeDeserializers.ObjectNodeDeserializer.Deserialize(IParser parser, Type expectedType, Func`3 nestedObjectDeserializer, Object& value, ObjectDeserializer rootDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.AliasValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.<>c__DisplayClass6_0.<DeserializeValue>b__1(IParser r, Type t)
   at YamlDotNet.Serialization.NodeDeserializers.DictionaryDeserializer.Deserialize(Type tKey, Type tValue, IParser parser, Func`3 nestedObjectDeserializer, IDictionary result, ObjectDeserializer rootDeserializer)
   at YamlDotNet.Serialization.NodeDeserializers.DictionaryNodeDeserializer.Deserialize(IParser parser, Type expectedType, Func`3 nestedObjectDeserializer, Object& value, ObjectDeserializer rootDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.AliasValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.<>c__DisplayClass6_0.<DeserializeValue>b__1(IParser r, Type t)
   at YamlDotNet.Serialization.NodeDeserializers.ObjectNodeDeserializer.Deserialize(IParser parser, Type expectedType, Func`3 nestedObjectDeserializer, Object& value, ObjectDeserializer rootDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.AliasValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
   at YamlDotNet.Serialization.Deserializer.Deserialize(IParser parser, Type type)
   at YamlDotNet.Serialization.Deserializer.Deserialize[T](IParser parser)
   at YamlDotNet.Serialization.Deserializer.Deserialize[T](TextReader input)
   at YamlDotNet.Serialization.Deserializer.Deserialize[T](String input)

iccfish avatar Feb 27 '25 03:02 iccfish

if I commit .WithNamingConvention(CamelCaseNamingConvention.Instance) and .WithNamingConvention(UnderscoredNamingConvention.Instance):

				//.WithNamingConvention(CamelCaseNamingConvention.Instance)
				//.WithNamingConvention(UnderscoredNamingConvention.Instance)

The above code shows different behaviour:

The value "System.Collections.Generic.Dictionary`2[System.String,System.String]" is not of type "System.String" and cannot be used in this generic collection. (Parameter 'value')

   at System.Collections.Generic.Dictionary`2.System.Collections.IDictionary.set_Item(Object key, Object value)
   at YamlDotNet.Serialization.NodeDeserializers.DictionaryDeserializer.TryAssign(IDictionary result, Object key, Object value, MappingStart propertyName)
   at YamlDotNet.Serialization.NodeDeserializers.DictionaryDeserializer.Deserialize(Type tKey, Type tValue, IParser parser, Func`3 nestedObjectDeserializer, IDictionary result, ObjectDeserializer rootDeserializer)
   at YamlDotNet.Serialization.NodeDeserializers.DictionaryNodeDeserializer.Deserialize(IParser parser, Type expectedType, Func`3 nestedObjectDeserializer, Object& value, ObjectDeserializer rootDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)

Seems if using WithNamingConvention, the YamlMember attribute will be ignored.

Thanks for your help.

iccfish avatar Feb 27 '25 10:02 iccfish