Microsoft.Azure.WebJobs.Extensions.AzureCosmosDb.Mongo/CosmosDBMongoConfigProvider.cs (130 lines of code) (raw):

// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. using Microsoft.Azure.WebJobs.Extensions.AzureCosmosDb.Mongo.Binding; using Microsoft.Azure.WebJobs.Host.Bindings; using Microsoft.Azure.WebJobs.Host.Config; using Microsoft.Azure.WebJobs.Logging; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using MongoDB.Bson; using MongoDB.Driver; using System; using System.Collections.Concurrent; using System.Collections.Generic; namespace Microsoft.Azure.WebJobs.Extensions.AzureCosmosDb.Mongo { public class CosmosDBMongoConfigProvider : IExtensionConfigProvider { private readonly ICosmosDBMongoBindingCollectorFactory _cosmosdbMongoBindingCollectorFactory; private readonly IConfiguration _configuration; private readonly INameResolver _nameResolver; private readonly ILoggerFactory _loggerFactory; private readonly ILogger _logger; private ConcurrentDictionary<string, IMongoClient> CollectorCache { get; } = new ConcurrentDictionary<string, IMongoClient>(); public CosmosDBMongoConfigProvider(ICosmosDBMongoBindingCollectorFactory cosmosdbMongoBindingCollectorFactory, IConfiguration configuration, INameResolver nameResolver, ILoggerFactory loggerFactory) { this._cosmosdbMongoBindingCollectorFactory = cosmosdbMongoBindingCollectorFactory; this._configuration = configuration; this._nameResolver = nameResolver; this._loggerFactory = loggerFactory; this._logger = loggerFactory.CreateLogger(LogCategories.CreateTriggerCategory(CosmosDBMongoConstant.AzureFunctionTelemetryCategory)); } public void Initialize(ExtensionConfigContext context) { if (context == null) { throw new ArgumentNullException("context"); } var triggerRule = context.AddBindingRule<CosmosDBMongoTriggerAttribute>(); triggerRule.AddValidator(ValidateTriggerConnection); triggerRule.BindToTrigger(new CosmosDBMongoTriggerBindingProvider(this._nameResolver, this, this._loggerFactory)); var bindingRule = context.AddBindingRule<CosmosDBMongoAttribute>(); bindingRule.AddValidator(ValidateConnection); bindingRule.BindToCollector<OpenType.Poco>(typeof(CosmosDBMongoBindingCollectorBuilder<>), this, this._loggerFactory); bindingRule.BindToInput<IEnumerable<OpenType.Poco>>(typeof(CosmosDBMongoBindingEnumerableBuilder<>), this); bindingRule.BindToInput<List<OpenType.Poco>>(typeof(CosmosDBMongoBindingListBuilder<>), this); bindingRule.WhenIsNull(nameof(CosmosDBMongoAttribute.DatabaseName)) .BindToInput(attribute => { return _cosmosdbMongoBindingCollectorFactory.CreateClient(ResolveConnectionString(attribute.ConnectionStringSetting)); }); bindingRule.WhenIsNull(nameof(CosmosDBMongoAttribute.CollectionName)).WhenIsNotNull(nameof(CosmosDBMongoAttribute.DatabaseName)) .BindToInput(attribute => { return _cosmosdbMongoBindingCollectorFactory.CreateClient(ResolveConnectionString(attribute.ConnectionStringSetting)).GetDatabase(attribute.DatabaseName); }); bindingRule.WhenIsNotNull(nameof(CosmosDBMongoAttribute.CollectionName)).WhenIsNotNull(nameof(CosmosDBMongoAttribute.DatabaseName)) .BindToInput(attribute => { return _cosmosdbMongoBindingCollectorFactory.CreateClient(ResolveConnectionString(attribute.ConnectionStringSetting)) .GetDatabase(attribute.DatabaseName) .GetCollection<BsonDocument>(attribute.CollectionName); }); } internal CosmosDBMongoTriggerContext CreateTriggerContext(CosmosDBMongoTriggerAttribute attribute) { IMongoClient client = GetService(attribute.ConnectionStringSetting, attribute.DatabaseName, attribute.CollectionName); return new CosmosDBMongoTriggerContext { MongoClient = client, ResolvedAttribute = attribute, }; } internal IMongoClient GetService(string connectionString, string databaseName, string collectionName) { string cacheKey = BuildCacheKey(connectionString, databaseName, collectionName); return CollectorCache.GetOrAdd(cacheKey, (c) => this._cosmosdbMongoBindingCollectorFactory.CreateClient(connectionString)); } internal void ValidateConnection(CosmosDBMongoAttribute attribute, Type paramType) { if (string.IsNullOrEmpty(ResolveConnectionString(attribute.ConnectionStringSetting))) { string attributeProperty = $"{nameof(CosmosDBMongoAttribute)}.{nameof(CosmosDBMongoAttribute.ConnectionStringSetting)}"; throw new InvalidOperationException( $"Connection string must be set via the {attributeProperty} property."); } } internal void ValidateTriggerConnection(CosmosDBMongoTriggerAttribute attribute, Type paramType) { if (string.IsNullOrEmpty(attribute.ConnectionStringSetting)) { string attributeProperty = $"{nameof(CosmosDBMongoTriggerAttribute)}.{nameof(CosmosDBMongoTriggerAttribute.ConnectionStringSetting)}"; throw new InvalidOperationException( $"Connection string must be set via the {attributeProperty} property."); } } internal IMongoClient GetService(string connection) { return _cosmosdbMongoBindingCollectorFactory.CreateClient(connection); } internal MongoCollectionReference ResolveCollectionReference(CosmosDBMongoAttribute attribute) { return new MongoCollectionReference( GetService(ResolveConnectionString(attribute.ConnectionStringSetting)), attribute.DatabaseName, attribute.CollectionName); } public string ResolveConnectionString(string connectionStringKey) { if (string.IsNullOrEmpty(connectionStringKey)) { connectionStringKey = CosmosDBMongoConstant.DefaultConnectionStringKey; } string connection = _configuration.GetConnectionString(connectionStringKey); if (string.IsNullOrEmpty(connection)) { connection = _configuration.GetValue<string>(connectionStringKey); } if (string.IsNullOrEmpty(connection)) { connection = _configuration.GetWebJobsConnectionString(connectionStringKey); } if (string.IsNullOrEmpty(connection)) { throw new InvalidOperationException($"Connection configuration '{connectionStringKey}' does not exist. " + $"Make sure that it is a defined App Setting or environment variable."); } return connection; } private static string BuildCacheKey(string connectionString, string databaseName, string collectionName) => $"{connectionString}|{databaseName}|{collectionName}"; } }