/// <summary> /// Provide a functional implementation corresponding to the enum value. /// </summary> public static SubjectNameStrategyDelegate ToDelegate(this SubjectNameStrategy strategy) { switch (strategy) { case SubjectNameStrategy.Topic: return((context, recordType) => $"{context.Topic}" + (context.Component == MessageComponentType.Key ? "-key" : "-value")); case SubjectNameStrategy.Record: return((context, recordType) => { if (recordType == null) { throw new ArgumentNullException($"recordType must not be null for SubjectNameStrategy.Record"); } return $"{recordType}"; }); case SubjectNameStrategy.TopicRecord: return((context, recordType) => { if (recordType == null) { throw new ArgumentNullException($"recordType must not be null for SubjectNameStrategy.Record"); } return $"{context.Topic}-{recordType}"; }); default: throw new ArgumentException($"Unknown SubjectNameStrategy: {strategy}"); } }
private static SubjectNameStrategy GetValueSubjectNameStrategy(IEnumerable <KeyValuePair <string, string> > config) { var valueSubjectNameStrategyString = config.FirstOrDefault(prop => prop.Key.ToLower() == SchemaRegistryConfig.PropertyNames.SchemaRegistryValueSubjectNameStrategy).Value ?? ""; SubjectNameStrategy valueSubjectNameStrategy = SubjectNameStrategy.Topic; if (valueSubjectNameStrategyString != "" && !Enum.TryParse <SubjectNameStrategy>(valueSubjectNameStrategyString, out valueSubjectNameStrategy)) { throw new ArgumentException($"Unknown ValueSubjectNameStrategy: {valueSubjectNameStrategyString}"); } return(valueSubjectNameStrategy); }
/// <summary> /// Initialize a new instance of the SchemaRegistryClient class. /// </summary> /// <param name="config"> /// Configuration properties. /// </param> public CachedSchemaRegistryClient(IEnumerable <KeyValuePair <string, string> > config) { if (config == null) { throw new ArgumentNullException("config properties must be specified."); } var schemaRegistryUrisMaybe = config.FirstOrDefault(prop => prop.Key.ToLower() == SchemaRegistryConfig.PropertyNames.SchemaRegistryUrl); if (schemaRegistryUrisMaybe.Value == null) { throw new ArgumentException($"{SchemaRegistryConfig.PropertyNames.SchemaRegistryUrl} configuration property must be specified."); } var schemaRegistryUris = (string)schemaRegistryUrisMaybe.Value; var timeoutMsMaybe = config.FirstOrDefault(prop => prop.Key.ToLower() == SchemaRegistryConfig.PropertyNames.SchemaRegistryRequestTimeoutMs); int timeoutMs; try { timeoutMs = timeoutMsMaybe.Value == null ? DefaultTimeout : Convert.ToInt32(timeoutMsMaybe.Value); } catch (FormatException) { throw new ArgumentException($"Configured value for {SchemaRegistryConfig.PropertyNames.SchemaRegistryRequestTimeoutMs} must be an integer."); } var identityMapCapacityMaybe = config.FirstOrDefault(prop => prop.Key.ToLower() == SchemaRegistryConfig.PropertyNames.SchemaRegistryMaxCachedSchemas); try { this.identityMapCapacity = identityMapCapacityMaybe.Value == null ? DefaultMaxCachedSchemas : Convert.ToInt32(identityMapCapacityMaybe.Value); } catch (FormatException) { throw new ArgumentException($"Configured value for {SchemaRegistryConfig.PropertyNames.SchemaRegistryMaxCachedSchemas} must be an integer."); } var basicAuthSource = config.FirstOrDefault(prop => prop.Key.ToLower() == SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthCredentialsSource).Value ?? ""; var basicAuthInfo = config.FirstOrDefault(prop => prop.Key.ToLower() == SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthUserInfo).Value ?? ""; string username = null; string password = null; if (basicAuthSource == "USER_INFO" || basicAuthSource == "") { if (basicAuthInfo != "") { var userPass = (basicAuthInfo).Split(':'); if (userPass.Length != 2) { throw new ArgumentException($"Configuration property {SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthUserInfo} must be of the form 'username:password'."); } username = userPass[0]; password = userPass[1]; } } else if (basicAuthSource == "SASL_INHERIT") { if (basicAuthInfo != "") { throw new ArgumentException($"{SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthCredentialsSource} set to 'SASL_INHERIT', but {SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthUserInfo} as also specified."); } var saslUsername = config.FirstOrDefault(prop => prop.Key == "sasl.username"); var saslPassword = config.FirstOrDefault(prop => prop.Key == "sasl.password"); if (saslUsername.Value == null) { throw new ArgumentException($"{SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthCredentialsSource} set to 'SASL_INHERIT', but 'sasl.username' property not specified."); } if (saslPassword.Value == null) { throw new ArgumentException($"{SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthCredentialsSource} set to 'SASL_INHERIT', but 'sasl.password' property not specified."); } username = saslUsername.Value; password = saslPassword.Value; } else { throw new ArgumentException($"Invalid value '{basicAuthSource}' specified for property '{SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthCredentialsSource}'"); } var schemaRegistrySecurityProtocol = config.FirstOrDefault(prop => prop.Key.ToLower() == SchemaRegistryConfig.PropertyNames.SchemaRegistrySecurityProtocol).Value ?? ""; // read new SSL properties string pfxCertificatePath = string.Empty; if (schemaRegistrySecurityProtocol.ToUpper() == "SSL") { pfxCertificatePath = config.FirstOrDefault(prop => prop.Key.ToLower() == SchemaRegistryConfig.PropertyNames.SchemaRegistryPfx).Value ?? ""; if (string.IsNullOrEmpty(pfxCertificatePath) || !File.Exists(pfxCertificatePath)) { throw new ArgumentException($"can't locate provided certificate at: {pfxCertificatePath}"); } } KeySubjectNameStrategy = GetKeySubjectNameStrategy(config); ValueSubjectNameStrategy = GetValueSubjectNameStrategy(config); foreach (var property in config) { if (!property.Key.StartsWith("schema.registry.")) { continue; } if (property.Key != SchemaRegistryConfig.PropertyNames.SchemaRegistryUrl && property.Key != SchemaRegistryConfig.PropertyNames.SchemaRegistryRequestTimeoutMs && property.Key != SchemaRegistryConfig.PropertyNames.SchemaRegistryMaxCachedSchemas && property.Key != SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthCredentialsSource && property.Key != SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthUserInfo && property.Key != SchemaRegistryConfig.PropertyNames.SchemaRegistryKeySubjectNameStrategy && property.Key != SchemaRegistryConfig.PropertyNames.SchemaRegistryValueSubjectNameStrategy && property.Key != SchemaRegistryConfig.PropertyNames.SchemaRegistrySecurityProtocol && // check new property property.Key != SchemaRegistryConfig.PropertyNames.SchemaRegistryPfx) // check new property { throw new ArgumentException($"Unknown configuration parameter {property.Key}"); } } if (!string.IsNullOrEmpty(pfxCertificatePath)) { this.restService = new RestService(schemaRegistryUris, timeoutMs, pfxCertificatePath); } else { this.restService = new RestService(schemaRegistryUris, timeoutMs, username, password); } }
/// <summary> /// Helper method to construct the value subject name given the specified parameters. /// </summary> public static string ConstructValueSubjectName(this SubjectNameStrategy strategy, string topic, string recordType = null) => strategy.ToDelegate()(new SerializationContext(MessageComponentType.Value, topic), recordType);
private static void ProduceConsume(string bootstrapServers, string schemaRegistryServers, SubjectNameStrategy nameStrategy) { var producerConfig = new ProducerConfig { BootstrapServers = bootstrapServers }; var consumerConfig = new ConsumerConfig { BootstrapServers = bootstrapServers, GroupId = Guid.NewGuid().ToString(), SessionTimeoutMs = 6000, AutoOffsetReset = AutoOffsetReset.Earliest, EnablePartitionEof = true }; var schemaRegistryConfig = new SchemaRegistryConfig { Url = schemaRegistryServers, // Test ValueSubjectNameStrategy here, // and KeySubjectNameStrategy in ProduceConsumeGeneric. ValueSubjectNameStrategy = nameStrategy }; var adminClientConfig = new AdminClientConfig { BootstrapServers = bootstrapServers }; string topic = Guid.NewGuid().ToString(); using (var adminClient = new AdminClientBuilder(adminClientConfig).Build()) { adminClient.CreateTopicsAsync( new List <TopicSpecification> { new TopicSpecification { Name = topic, NumPartitions = 1, ReplicationFactor = 1 } }).Wait(); } using (var schemaRegistry = new CachedSchemaRegistryClient(schemaRegistryConfig)) using (var producer = new ProducerBuilder <string, ProduceConsumeUser>(producerConfig) .SetKeySerializer(new AvroSerializer <string>(schemaRegistry)) .SetValueSerializer(new AvroSerializer <ProduceConsumeUser>(schemaRegistry)) .Build()) { for (int i = 0; i < 100; ++i) { var user = new ProduceConsumeUser { name = i.ToString(), favorite_number = i, favorite_color = "blue" }; producer .ProduceAsync(topic, new Message <string, ProduceConsumeUser> { Key = user.name, Value = user }) .Wait(); } Assert.Equal(0, producer.Flush(TimeSpan.FromSeconds(10))); } using (var schemaRegistry = new CachedSchemaRegistryClient(schemaRegistryConfig)) using (var consumer = new ConsumerBuilder <string, ProduceConsumeUser>(consumerConfig) .SetKeyDeserializer(new AvroDeserializer <string>(schemaRegistry).AsSyncOverAsync()) .SetValueDeserializer(new AvroDeserializer <ProduceConsumeUser>(schemaRegistry).AsSyncOverAsync()) .SetErrorHandler((_, e) => Assert.True(false, e.Reason)) .Build()) { consumer.Subscribe(topic); int i = 0; while (true) { var record = consumer.Consume(TimeSpan.FromMilliseconds(100)); if (record == null) { continue; } if (record.IsPartitionEOF) { break; } Assert.Equal(i.ToString(), record.Message.Key); Assert.Equal(i.ToString(), record.Message.Value.name); Assert.Equal(i, record.Message.Value.favorite_number); Assert.Equal("blue", record.Message.Value.favorite_color); i += 1; } Assert.Equal(100, i); consumer.Close(); } // Check that what's in schema registry is what's expected. using (var schemaRegistry = new CachedSchemaRegistryClient(schemaRegistryConfig)) { var subjects = schemaRegistry.GetAllSubjectsAsync().Result; if (nameStrategy == SubjectNameStrategy.TopicRecord) { Assert.Equal(2, (int)subjects.Where(s => s.Contains(topic)).Count()); Assert.Single(subjects.Where(s => s == $"{topic}-key")); Assert.Single(subjects.Where(s => s == $"{topic}-{((Avro.RecordSchema)ProduceConsumeUser._SCHEMA).Fullname}")); } if (nameStrategy == SubjectNameStrategy.Topic) { Assert.Equal(2, (int)subjects.Where(s => s.Contains(topic)).Count()); Assert.Single(subjects.Where(s => s == $"{topic}-key")); Assert.Single(subjects.Where(s => s == $"{topic}-value")); } if (nameStrategy == SubjectNameStrategy.Record) { Assert.Single(subjects.Where(s => s.Contains(topic))); // the string key. Assert.Single(subjects.Where(s => s == $"{topic}-key")); Assert.Single(subjects.Where(s => s == $"{((Avro.RecordSchema)ProduceConsumeUser._SCHEMA).Fullname}")); } } }
private static void ProduceConsumeNull(string bootstrapServers, string schemaRegistryServers, SubjectNameStrategy nameStrategy) { var producerConfig = new ProducerConfig { BootstrapServers = bootstrapServers }; var consumerConfig = new ConsumerConfig { BootstrapServers = bootstrapServers, GroupId = Guid.NewGuid().ToString(), SessionTimeoutMs = 6000, AutoOffsetReset = AutoOffsetReset.Earliest, EnablePartitionEof = true }; var schemaRegistryConfig = new SchemaRegistryConfig { Url = schemaRegistryServers, }; var avroSerializerConfig = new AvroSerializerConfig { SubjectNameStrategy = nameStrategy }; var adminClientConfig = new AdminClientConfig { BootstrapServers = bootstrapServers }; string topic = Guid.NewGuid().ToString(); using (var adminClient = new AdminClientBuilder(adminClientConfig).Build()) { adminClient.CreateTopicsAsync( new List <TopicSpecification> { new TopicSpecification { Name = topic, NumPartitions = 1, ReplicationFactor = 1 } }).Wait(); } using (var schemaRegistry = new CachedSchemaRegistryClient(schemaRegistryConfig)) using (var producer = new ProducerBuilder <string, ProduceConsumeUser>(producerConfig) .SetKeySerializer(new AvroSerializer <string>(schemaRegistry)) // Test ValueSubjectNameStrategy here, // and KeySubjectNameStrategy in ProduceConsumeGeneric. .SetValueSerializer(new AvroSerializer <ProduceConsumeUser>(schemaRegistry, avroSerializerConfig)) .Build()) { for (int i = 0; i < 100; ++i) { producer .ProduceAsync(topic, new Message <string, ProduceConsumeUser> { Key = null, Value = null }) .Wait(); } Assert.Equal(0, producer.Flush(TimeSpan.FromSeconds(10))); } using (var schemaRegistry = new CachedSchemaRegistryClient(schemaRegistryConfig)) using (var consumer = new ConsumerBuilder <string, ProduceConsumeUser>(consumerConfig) .SetKeyDeserializer(new AvroDeserializer <string>(schemaRegistry).AsSyncOverAsync()) .SetValueDeserializer(new AvroDeserializer <ProduceConsumeUser>(schemaRegistry).AsSyncOverAsync()) .SetErrorHandler((_, e) => Assert.True(false, e.Reason)) .Build()) { consumer.Subscribe(topic); int i = 0; while (true) { var record = consumer.Consume(TimeSpan.FromMilliseconds(100)); if (record == null) { continue; } if (record.IsPartitionEOF) { break; } Assert.Null(record.Message.Key); Assert.Null(record.Message.Value); i += 1; } Assert.Equal(100, i); consumer.Close(); } }
private static void ProduceConsumeGeneric(string bootstrapServers, string schemaRegistryServers, SubjectNameStrategy nameStrategy) { var rs = (RecordSchema)RecordSchema.Parse( @"{ ""namespace"": ""Confluent.Kafka.Examples.AvroSpecific"", ""type"": ""record"", ""name"": ""ProduceConsumeUser2"", ""fields"": [ {""name"": ""name"", ""type"": ""string""}, {""name"": ""favorite_number"", ""type"": [""int"", ""null""]}, {""name"": ""favorite_color"", ""type"": [""string"", ""null""]} ] }" ); var config = new ProducerConfig { BootstrapServers = bootstrapServers }; var schemaRegistryConfig = new SchemaRegistryConfig { Url = schemaRegistryServers, }; var avroSerializerConfig = new AvroSerializerConfig { SubjectNameStrategy = nameStrategy }; var topic = Guid.NewGuid().ToString(); DeliveryResult <GenericRecord, Null> dr; using (var schemaRegistry = new CachedSchemaRegistryClient(schemaRegistryConfig)) using (var p = new ProducerBuilder <GenericRecord, Null>(config) // Test KeySubjectNameStrategy here, // and ValueSubjectNameStrategy in ProduceConsume. .SetKeySerializer(new AvroSerializer <GenericRecord>(schemaRegistry, avroSerializerConfig)) .SetValueSerializer(Serializers.Null) .Build()) { var record = new GenericRecord(rs); record.Add("name", "my name 2"); record.Add("favorite_number", 44); record.Add("favorite_color", null); dr = p.ProduceAsync(topic, new Message <GenericRecord, Null> { Key = record }).Result; } // produce a specific record (to later consume back as a generic record). using (var schemaRegistry = new CachedSchemaRegistryClient(schemaRegistryConfig)) using (var p = new ProducerBuilder <ProduceConsumeUser2, Null>(config) .SetKeySerializer(new AvroSerializer <ProduceConsumeUser2>(schemaRegistry, avroSerializerConfig)) .SetValueSerializer(Serializers.Null) .Build()) { var user = new ProduceConsumeUser2 { name = "my name 3", favorite_number = 47, favorite_color = "orange" }; p.ProduceAsync(topic, new Message <ProduceConsumeUser2, Null> { Key = user }).Wait(); } Assert.Null(dr.Message.Value); Assert.NotNull(dr.Message.Key); dr.Message.Key.TryGetValue("name", out object name); dr.Message.Key.TryGetValue("favorite_number", out object number); dr.Message.Key.TryGetValue("favorite_color", out object color); Assert.IsType <string>(name); Assert.IsType <int>(number); Assert.Equal("my name 2", name); Assert.Equal(44, number); Assert.Null(color); var cconfig = new ConsumerConfig { GroupId = Guid.NewGuid().ToString(), BootstrapServers = bootstrapServers }; using (var schemaRegistry = new CachedSchemaRegistryClient(schemaRegistryConfig)) using (var consumer = new ConsumerBuilder <GenericRecord, Null>(cconfig) .SetKeyDeserializer(new AvroDeserializer <GenericRecord>(schemaRegistry).AsSyncOverAsync()) .SetValueDeserializer(Deserializers.Null) .Build()) { // consume generic record produced as a generic record. consumer.Assign(new List <TopicPartitionOffset> { new TopicPartitionOffset(topic, 0, dr.Offset) }); var record = consumer.Consume(new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token); record.Message.Key.TryGetValue("name", out object msgName); record.Message.Key.TryGetValue("favorite_number", out object msgNumber); record.Message.Key.TryGetValue("favorite_color", out object msgColor); Assert.IsType <string>(msgName); Assert.IsType <int>(msgNumber); Assert.Equal("my name 2", msgName); Assert.Equal(44, msgNumber); Assert.Null(msgColor); // consume generic record produced as a specific record. record = consumer.Consume(new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token); record.Message.Key.TryGetValue("name", out msgName); record.Message.Key.TryGetValue("favorite_number", out msgNumber); record.Message.Key.TryGetValue("favorite_color", out msgColor); Assert.IsType <string>(msgName); Assert.IsType <int>(msgNumber); Assert.IsType <string>(msgColor); Assert.Equal("my name 3", msgName); Assert.Equal(47, msgNumber); Assert.Equal("orange", msgColor); } using (var schemaRegistry = new CachedSchemaRegistryClient(schemaRegistryConfig)) using (var consumer = new ConsumerBuilder <ProduceConsumeUser2, Null>(cconfig) .SetKeyDeserializer(new AvroDeserializer <ProduceConsumeUser2>(schemaRegistry).AsSyncOverAsync()) .SetValueDeserializer(Deserializers.Null) .Build()) { consumer.Assign(new List <TopicPartitionOffset> { new TopicPartitionOffset(topic, 0, dr.Offset) }); var record = consumer.Consume(new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token); Assert.Equal("my name 2", record.Message.Key.name); Assert.Equal(44, record.Message.Key.favorite_number); Assert.Null(record.Message.Key.favorite_color); } // Check that what's in schema registry is what's expected. using (var schemaRegistry = new CachedSchemaRegistryClient(schemaRegistryConfig)) { var subjects = schemaRegistry.GetAllSubjectsAsync().Result; if (nameStrategy == SubjectNameStrategy.TopicRecord) { Assert.Single(subjects.Where(s => s.Contains(topic))); Assert.Single(subjects.Where(s => s == $"{topic}-{((Avro.RecordSchema)ProduceConsumeUser2._SCHEMA).Fullname}")); } if (nameStrategy == SubjectNameStrategy.Topic) { Assert.Single(subjects.Where(s => s.Contains(topic))); Assert.Single(subjects.Where(s => s == $"{topic}-key")); } if (nameStrategy == SubjectNameStrategy.Record) { Assert.Single(subjects.Where(s => s.Contains(topic))); // the string key. Assert.Single(subjects.Where(s => s == $"{((Avro.RecordSchema)ProduceConsumeUser2._SCHEMA).Fullname}")); } } }
/// <summary> /// Initialize a new instance of the SchemaRegistryClient class. /// </summary> /// <param name="config"> /// Configuration properties. /// </param> public CachedSchemaRegistryClient(IEnumerable <KeyValuePair <string, string> > config) { if (config == null) { throw new ArgumentNullException("config properties must be specified."); } var schemaRegistryUrisMaybe = config.FirstOrDefault(prop => prop.Key.ToLower() == SchemaRegistryConfig.PropertyNames.SchemaRegistryUrl); if (schemaRegistryUrisMaybe.Value == null) { throw new ArgumentException($"{SchemaRegistryConfig.PropertyNames.SchemaRegistryUrl} configuration property must be specified."); } var schemaRegistryUris = (string)schemaRegistryUrisMaybe.Value; var timeoutMsMaybe = config.FirstOrDefault(prop => prop.Key.ToLower() == SchemaRegistryConfig.PropertyNames.SchemaRegistryRequestTimeoutMs); int timeoutMs; try { timeoutMs = timeoutMsMaybe.Value == null ? DefaultTimeout : Convert.ToInt32(timeoutMsMaybe.Value); } catch (FormatException) { throw new ArgumentException($"Configured value for {SchemaRegistryConfig.PropertyNames.SchemaRegistryRequestTimeoutMs} must be an integer."); } var identityMapCapacityMaybe = config.FirstOrDefault(prop => prop.Key.ToLower() == SchemaRegistryConfig.PropertyNames.SchemaRegistryMaxCachedSchemas); try { this.identityMapCapacity = identityMapCapacityMaybe.Value == null ? DefaultMaxCachedSchemas : Convert.ToInt32(identityMapCapacityMaybe.Value); } catch (FormatException) { throw new ArgumentException($"Configured value for {SchemaRegistryConfig.PropertyNames.SchemaRegistryMaxCachedSchemas} must be an integer."); } var basicAuthSource = Convert.ToString(config.FirstOrDefault(prop => prop.Key.ToLower() == SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthCredentialsSource).Value) ?? ""; var basicAuthInfo = Convert.ToString(config.FirstOrDefault(prop => prop.Key.ToLower() == SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthUserInfo).Value) ?? ""; string username = null; string password = null; if (basicAuthSource == "USER_INFO" || basicAuthSource == "") { if (basicAuthInfo != "") { var userPass = (basicAuthInfo).Split(':'); if (userPass.Length != 2) { throw new ArgumentException($"Configuration property {SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthUserInfo} must be of the form 'username:password'."); } username = userPass[0]; password = userPass[1]; } } else if (basicAuthSource == "SASL_INHERIT") { if (basicAuthInfo != "") { throw new ArgumentException($"{SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthCredentialsSource} set to 'SASL_INHERIT', but {SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthUserInfo} as also specified."); } var saslUsername = config.FirstOrDefault(prop => prop.Key == "sasl.username"); var saslPassword = config.FirstOrDefault(prop => prop.Key == "sasl.password"); if (saslUsername.Value == null) { throw new ArgumentException($"{SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthCredentialsSource} set to 'SASL_INHERIT', but 'sasl.username' property not specified."); } if (saslPassword.Value == null) { throw new ArgumentException($"{SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthCredentialsSource} set to 'SASL_INHERIT', but 'sasl.password' property not specified."); } username = Convert.ToString(saslUsername.Value); password = Convert.ToString(saslPassword.Value); } else { throw new ArgumentException($"Invalid value '{basicAuthSource}' specified for property '{SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthCredentialsSource}'"); } var keySubjNameStrategy = Convert.ToString(config.FirstOrDefault(prop => prop.Key.ToLower() == SchemaRegistryConfig.PropertyNames.SchemaRegistryKeySubjectNameStrategy).Value) ?? ""; var valueSubjNameStrategy = Convert.ToString(config.FirstOrDefault(prop => prop.Key.ToLower() == SchemaRegistryConfig.PropertyNames.SchemaRegistryValueSubjectNameStrategy).Value) ?? ""; if (Enum.TryParse <SubjectNameStrategy>(keySubjNameStrategy, out var strategy)) { KeySubjectNameStrategy = strategy; } if (Enum.TryParse <SubjectNameStrategy>(valueSubjNameStrategy, out strategy)) { ValueSubjectNameStrategy = strategy; } foreach (var property in config) { if (!property.Key.StartsWith("schema.registry.")) { continue; } if (property.Key != SchemaRegistryConfig.PropertyNames.SchemaRegistryUrl && property.Key != SchemaRegistryConfig.PropertyNames.SchemaRegistryRequestTimeoutMs && property.Key != SchemaRegistryConfig.PropertyNames.SchemaRegistryMaxCachedSchemas && property.Key != SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthCredentialsSource && property.Key != SchemaRegistryConfig.PropertyNames.SchemaRegistryBasicAuthUserInfo && property.Key != SchemaRegistryConfig.PropertyNames.SchemaRegistryKeySubjectNameStrategy && property.Key != SchemaRegistryConfig.PropertyNames.SchemaRegistryValueSubjectNameStrategy) { throw new ArgumentException($"Unknown configuration parameter {property.Key}"); } } this.restService = new RestService(schemaRegistryUris, timeoutMs, username, password); }