private static void InitializeDatabase(bool isTestMode, DocCollectionSettings collectionSettings) { // create shared document client for this collection. If you had multiple collections // we could refactor the settings a little (since the connection keys would be the same) // Can also share the connection across collections. But we only have one.. if (!isTestMode) { collectionSettings.DocumentClient = new DocumentClient(new Uri(collectionSettings.EndpointUri), collectionSettings.AccessKey); } }
private void ConfigureDataConnection(IServiceCollection services) { var isTestMode = Configuration.GetValue <bool>("Testing:TestMode", false); var cosmosAccountName = Configuration.GetValue <string>("Cosmos:volunteer:AccountName"); var primaryAccessKey = Configuration.GetValue <string>("Cosmos:volunteer:AccountKey"); // use dev database when using local SPA. Local SPA currently points to the Test Tier var isTestTier = Configuration.GetValue <bool>("Cosmos:volunteer:TestTier", false); if (isTestTier) { cosmosAccountName = "vol-dev"; primaryAccessKey = "ZFo6oKcYVMlTjM4nosQg94Z12qscna0lvBOlhnpKbmlIs0pDzqt0yiZs50qFsWyFYA2kadhISB8wOvrdSYZFnw=="; } var endpointUri = $"https://{cosmosAccountName}.documents.azure.com:443/"; if (string.IsNullOrEmpty(cosmosAccountName)) { throw new Exception("cosmosAccountName empty"); } if (string.IsNullOrEmpty(primaryAccessKey)) { throw new Exception("primaryAccessKey empty"); } var databaseId = Configuration.GetValue <string>("Cosmos:volunteer:DatabaseId"); var volCollection = Configuration.GetValue <string>("Cosmos:volunteer:Volunteer:Collection"); var partitionKey = Configuration.GetValue <string>("Cosmos:volunteer:Volunteer:PartitionKey"); var throughput = Configuration.GetValue <int>("Cosmos:volunteer:Volunteer:Throughput"); if (string.IsNullOrEmpty(databaseId)) { throw new Exception("databaseId empty"); } if (string.IsNullOrEmpty(volCollection)) { throw new Exception("collection empty"); } if (string.IsNullOrEmpty(partitionKey)) { throw new Exception("partitionKey empty"); } // Volunteer collection settings, these will get injected into the DocCollection singleton // migrating to this pattern of having each collection manage/factory its repos, // manage its migrations for stored procs, and other collection-level stuff // ... // need to figure out how a muti-collection app can use this pattern... // ... // might have it! // ... // in order to create different DocCollection objects (one for each collection) that can still be injected as singletons, we could // create a generic DocCollection concept somehow? How can we associate a collection with an instance of a generic? We could create // unique DocCollectionSettings with inheritence, like so.. // ... // Church congregant service has multiple collections and uses a DataAdapter (ex: ICongregantInfoDataAdapter) // Not sure at this time if we want multiple collections or not. Using one for now, if we find we want more, copy their pattern. // https://blackbaud.visualstudio.com/Products/Products%20Team/_git/chu-congregant-svc?path=%2Fsrc%2FBlackbaud.Church.CongregantService%2FStartup.cs&version=GBmaster&line=53&lineEnd=54&lineStartColumn=1&lineEndColumn=1&lineStyle=plain var collectionSettings = new DocCollectionSettings() { AccessKey = primaryAccessKey, DatabaseId = databaseId, EndpointUri = endpointUri, CollectionId = volCollection, PartitionPath = $"/{partitionKey}", DocumentClient = null, InitializeAutomatically = false }; // Create Wrapper Object for Document Client var collectionClient = new DocumentClient(new Uri(endpointUri), primaryAccessKey); var partitionPaths = new Collection <string>(); partitionPaths.Add(collectionSettings.PartitionPath); var partitionKeyDef = new PartitionKeyDefinition() { Paths = partitionPaths }; if (!isTestMode) { var collectionWithThroughput = collectionClient.CreateDocumentCollectionIfNotExistsAsync( UriFactory.CreateDatabaseUri(databaseId), new DocumentCollection { Id = volCollection, PartitionKey = partitionKeyDef, // This allows us to do range queries against the dateTime props IndexingPolicy = new IndexingPolicy(new RangeIndex(DataType.String) { Precision = -1 }) }, new RequestOptions { OfferThroughput = throughput } ); collectionWithThroughput.Wait(); updateThroughput(collectionClient, collectionWithThroughput.Result.Resource.SelfLink, throughput); } var collectionUri = UriFactory.CreateDocumentCollectionUri(databaseId, volCollection); var clientHolder = new DocumentClientHolder() { Client = collectionClient, VolunteerCollectionUri = collectionUri }; Console.WriteLine("collectionSettings instantiated"); InitializeDatabase(isTestMode, collectionSettings); // Set up a Cache for services services.AddMemoryCache(); // now register a singleton for this specifc collection type's settings services.AddSingleton <DocCollectionSettings>(collectionSettings); services.AddSingleton <DocumentClientHolder>(clientHolder); // add more settings types here, for each collection... but we only have one. Ok, take it easy! // now register a singletons of a DocCollections that takes an associated settings type. // this syntax says "if a type of IDocCollection<fooSettings> is requested cough up DocCollection<fooSettings> as a singleton // so each collection gets its own singleton, with its own settings! Sweet. if (!isTestMode) { services.AddSingleton(typeof(IDocCollection <>), typeof(DocCollection <>)); } else { services.AddSingleton(typeof(IDocCollection <>), typeof(TestDocCollection <>)); } }