// This sample shows how to create a synonym-map and an index that are encrypted with customer-managed key in Azure Key Vault
        static void Main(string[] args)
        {
            IConfigurationBuilder builder       = new ConfigurationBuilder().AddJsonFile("appsettings.json");
            IConfigurationRoot    configuration = builder.Build();

            SearchIndexClient indexClient = CreateSearchIndexClient(configuration);

            Console.WriteLine("Cleaning up resources...\n");
            CleanupResources(indexClient);

            Console.WriteLine("Creating synonym-map encrypted with customer managed key...\n");
            CreateSynonymsEncryptedUsingCustomerManagedKey(indexClient, configuration);

            Console.WriteLine("Creating index encrypted with customer managed key...\n");
            CreateHotelsIndexEncryptedUsingCustomerManagedKey(indexClient, configuration);

            SearchIndex index = indexClient.GetIndex("hotels");

            index = AddSynonymMapsToFields(index);
            indexClient.CreateOrUpdateIndex(index);

            SearchClient searchClient = indexClient.GetSearchClient("hotels");

            Console.WriteLine("Uploading documents...\n");
            UploadDocuments(searchClient);

            SearchClient searchClientForQueries = CreateSearchClient(configuration);

            RunQueries(searchClientForQueries);

            Console.WriteLine("Complete.  Press any key to end application...\n");
            Console.ReadKey();
        }
Beispiel #2
0
        private static void CreateHotelsIndex(SearchIndexClient indexClient)
        {
            FieldBuilder fieldBuilder = new FieldBuilder();
            var          searchFields = fieldBuilder.Build(typeof(Hotel));
            var          searchIndex  = new SearchIndex("hotels", searchFields);

            indexClient.CreateOrUpdateIndex(searchIndex);
        }
        private static void CreateIndex(string indexName, SearchIndexClient indexClient)
        {
            FieldBuilder fieldBuilder = new FieldBuilder();
            var          searchFields = fieldBuilder.Build(typeof(Hotel));

            var definition = new SearchIndex(indexName, searchFields);

            indexClient.CreateOrUpdateIndex(definition);
        }
        private static void CreateHotelsIndexEncryptedUsingCustomerManagedKey(SearchIndexClient indexClient, IConfigurationRoot configuration)
        {
            FieldBuilder fieldBuilder = new FieldBuilder();
            var          searchFields = fieldBuilder.Build(typeof(Hotel));
            var          definition   = new SearchIndex("hotels", searchFields)
            {
                EncryptionKey = GetEncryptionKeyFromConfiguration(configuration)
            };

            indexClient.CreateOrUpdateIndex(definition);
        }
        // Create hotels-quickstart index
        private static void CreateIndex(string indexName, SearchIndexClient adminClient)
        {
            FieldBuilder fieldBuilder = new FieldBuilder();
            var          searchFields = fieldBuilder.Build(typeof(Hotel));

            var definition = new SearchIndex(indexName, searchFields);

            var suggester = new SearchSuggester("sg", new[] { "HotelName", "Category", "Address/City", "Address/StateProvince" });

            definition.Suggesters.Add(suggester);

            adminClient.CreateOrUpdateIndex(definition);
        }
        private static void CreateIndex(string indexName)
        {
            // Create the Azure Search index based on the included schema
            try
            {
                FieldBuilder fieldBuilder = new FieldBuilder();
                var          searchFields = fieldBuilder.Build(typeof(SecuredFiles));
                var          definition   = new SearchIndex(indexName, searchFields);

                indexClient.CreateOrUpdateIndex(definition);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error creating index: {0}\r\n", ex.Message);
                throw;
            }
        }
Beispiel #7
0
        /// <summary>
        /// Crea o actualiza el índice en el azure search.
        /// </summary>
        public void CreateOrUpdateIndex()
        {
            var indexName = Index;
            // creación del índice.
            FieldBuilder fieldBuilder = new FieldBuilder();
            var          searchFields = fieldBuilder.Build(typeof(EntitySearch));

            var definition  = new SearchIndex(indexName, searchFields);
            var cors_option = new CorsOptions(new List <string> {
                "*"
            });

            cors_option.MaxAgeInSeconds = 300;
            definition.CorsOptions      = cors_option;
            definition.Suggesters.Add(new SearchSuggester("sug", new List <string> {
                "sug/value"
            }));
            //definition.CorsOptions = this.corsOptions;
            _searchIndex.CreateOrUpdateIndex(definition);
        }
Beispiel #8
0
        private static void CreateIndex(string indexName, SearchIndexClient adminClient)
        {
            FieldBuilder        fieldBuilder = new();
            IList <SearchField> searchFields = fieldBuilder.Build(typeof(Hotel));

            SearchIndex definition = new(indexName, searchFields);

            SearchSuggester suggester = new("sg", new[] { "HotelName", "Category", "Address/City", "Address/StateProvince" });

            definition.Suggesters.Add(suggester);

            adminClient.CreateOrUpdateIndex(definition);

            //// Call the RunQueries method to invoke a series of queries
            //Console.WriteLine("Starting queries...\n");
            //RunQueries(srchclient);

            //// End the program
            //Console.WriteLine("{0}", "Complete. Press any key to end this program...\n");
            //Console.ReadKey();
        }
Beispiel #9
0
        public SearchAPI(IOptions <Configuration.SearchOptions> options)
        {
            Uri endpointUri = new Uri(options.Value.Endpoint !);

            Azure.AzureKeyCredential credentials = new Azure.AzureKeyCredential(options.Value.AccessKey !);
            searchIndexClient = new SearchIndexClient(endpointUri, credentials);
            searchClient      = new SearchClient(endpointUri, IndexName, credentials);

            FieldBuilder fieldBuilder = new FieldBuilder();
            var          searchFields = fieldBuilder.Build(typeof(AlbumInfoSearchObject));

            var definition = new SearchIndex(IndexName, searchFields);
            var suggester  = new SearchSuggester("AlbumsSuggester",
                                                 new[] { nameof(AlbumInfoSearchObject.AlbumName),
                                                         nameof(AlbumInfoSearchObject.ArtistName),
                                                         nameof(AlbumInfoSearchObject.Colors),
                                                         nameof(AlbumInfoSearchObject.Tags),
                                                         nameof(AlbumInfoSearchObject.Captions) });

            definition.Suggesters.Add(suggester);
            searchIndexClient.CreateOrUpdateIndex(definition);
        }
Beispiel #10
0
        public void ConfigureSearchService(Dictionary <string, object> configurations, Type sourceType)
        {
            string id = sourceType.Name.ToLower();

            if (_searchClientProviderInfos.Any(x => x.Id == id))
            {
                return;
            }

            var    prefix    = configurations.GetStringValue(SearchConstants.Prefix, sourceType) ?? "";
            string indexName = prefix + id;

            _searchServiceClient.CreateOrUpdateIndex(new SearchIndex(indexName, GetTypeFields(sourceType, true)));

            _searchClientProviderInfos.Add(new SearchClientProviderInfo
            {
                Id = id,
                RequestContextSelector = configurations.ContainsKey(DocumentDbConfigurationExtensions.GetKey(SearchConstants.RequestContextSelector, sourceType)) ?
                                         configurations.GetValue <Func <IGraphRequestContext, bool> >(SearchConstants.RequestContextSelector, sourceType) : null,
                SearchIndexClient = new SearchClient(_serviceName.GetSearchServiceUri(), indexName, _azureKeyCredential)
            });
        }
Beispiel #11
0
        private static void EnableSynonymsInHotelsIndexSafely(SearchIndexClient indexClient)
        {
            int MaxNumTries = 3;

            for (int i = 0; i < MaxNumTries; ++i)
            {
                try
                {
                    SearchIndex index = indexClient.GetIndex("hotels");
                    index = AddSynonymMapsToFields(index);

                    // The IfNotChanged condition ensures that the index is updated only if the ETags match.
                    indexClient.CreateOrUpdateIndex(index);

                    Console.WriteLine("Updated the index successfully.\n");
                    break;
                }
                catch (CloudException)
                {
                    Console.WriteLine($"Index update failed : . Attempt({i}/{MaxNumTries}).\n");
                }
            }
        }
        public static async Task Main(string[] args)
        {
            IConfigurationBuilder builder       = new ConfigurationBuilder().AddJsonFile("appsettings.json");
            IConfigurationRoot    configuration = builder.Build();

            if (configuration["SearchServiceEndPoint"] == "Put your search service endpoint here")
            {
                Console.Error.WriteLine("Specify SearchServiceEndPoint in appsettings.json");
                Environment.Exit(-1);
            }

            if (configuration["SearchServiceAdminApiKey"] == "Put your search service admin API key here")
            {
                Console.Error.WriteLine("Specify SearchServiceAdminApiKey in appsettings.json");
                Environment.Exit(-1);
            }

            if (configuration["AzureSQLConnectionString"] == "Put your Azure SQL database connection string here")
            {
                Console.Error.WriteLine("Specify AzureSQLConnectionString in appsettings.json");
                Environment.Exit(-1);
            }

            SearchIndexClient   indexClient   = new SearchIndexClient(new Uri(configuration["SearchServiceEndPoint"]), new AzureKeyCredential(configuration["SearchServiceAdminApiKey"]));
            SearchIndexerClient indexerClient = new SearchIndexerClient(new Uri(configuration["SearchServiceEndPoint"]), new AzureKeyCredential(configuration["SearchServiceAdminApiKey"]));

            Console.WriteLine("Creating index...");
            FieldBuilder fieldBuilder = new FieldBuilder();
            var          searchFields = fieldBuilder.Build(typeof(Hotel));
            var          searchIndex  = new SearchIndex("hotels-sql-idx", searchFields);

            // If we have run the sample before, this index will be populated
            // We can clear the index by deleting it if it exists and creating
            // it again
            CleanupSearchIndexClientResources(indexClient, searchIndex);

            indexClient.CreateOrUpdateIndex(searchIndex);

            Console.WriteLine("Creating data source...");

            // The sample data set has a table name of "hotels"
            // The sample data set table has a "soft delete" column named IsDeleted
            // When this column is set to true and the indexer sees it, it will remove the
            // corresponding document from the search service
            // See this link for more information
            // https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.search.models.softdeletecolumndeletiondetectionpolicy
            // The sample data set uses SQL integrated change tracking for change detection
            // This means that when the indexer runs, it will be able to detect which data has
            // changed since the last run using built in change tracking
            // See this link for more information
            // https://docs.microsoft.com/en-us/sql/relational-databases/track-changes/about-change-tracking-sql-server
            var dataSource =
                new SearchIndexerDataSourceConnection(
                    "hotels-sql-ds",
                    SearchIndexerDataSourceType.AzureSql,
                    configuration["AzureSQLConnectionString"],
                    new SearchIndexerDataContainer("hotels"));

            // The data source does not need to be deleted if it was already created,
            // but the connection string may need to be updated if it was changed
            indexerClient.CreateOrUpdateDataSourceConnection(dataSource);

            Console.WriteLine("Creating Azure SQL indexer...");

            var schedule = new IndexingSchedule(TimeSpan.FromDays(1))
            {
                StartTime = DateTimeOffset.Now
            };

            var parameters = new IndexingParameters()
            {
                BatchSize              = 100,
                MaxFailedItems         = 0,
                MaxFailedItemsPerBatch = 0
            };

            // Indexer declarations require a data source and search index.
            // Common optional properties include a schedule, parameters, and field mappings
            // The field mappings below are redundant due to how the Hotel class is defined, but
            // we included them anyway to show the syntax
            var indexer = new SearchIndexer("hotels-sql-idxr", dataSource.Name, searchIndex.Name)
            {
                Description   = "Data indexer",
                Schedule      = schedule,
                Parameters    = parameters,
                FieldMappings =
                {
                    new FieldMapping("_id")
                    {
                        TargetFieldName = "HotelId"
                    },
                    new FieldMapping("Amenities")
                    {
                        TargetFieldName = "Tags"
                    }
                }
            };

            // Indexers contain metadata about how much they have already indexed
            // If we already ran the sample, the indexer will remember that it already
            // indexed the sample data and not run again
            // To avoid this, reset the indexer if it exists
            CleanupSearchIndexerClientResources(indexerClient, indexer);

            await indexerClient.CreateOrUpdateIndexerAsync(indexer);

            // We created the indexer with a schedule, but we also
            // want to run it immediately
            Console.WriteLine("Running Azure SQL indexer...");

            try
            {
                await indexerClient.RunIndexerAsync(indexer.Name);
            }
            catch (CloudException e) when(e.Response.StatusCode == (HttpStatusCode)429)
            {
                Console.WriteLine("Failed to run indexer: {0}", e.Response.Content);
            }

            // Wait 5 seconds for indexing to complete before checking status
            Console.WriteLine("Waiting for indexing...\n");
            System.Threading.Thread.Sleep(5000);

            // After an indexer run, you can retrieve status.
            CheckIndexerStatus(indexerClient, indexer);

            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
            Environment.Exit(0);
        }
        public void CreateCustomerIndex()
        {
            //creating index
            SearchIndexClient   indexClient   = new SearchIndexClient(Uri, keyCredential);
            SearchIndexerClient indexerClient = new SearchIndexerClient(Uri, keyCredential);

            Console.WriteLine("Creating index...");
            FieldBuilder fieldBuilder = new FieldBuilder();
            var          searchFields = fieldBuilder.Build(typeof(ServiceOrder));
            //var searchIndex = new SearchIndex("serviceorder-sql-idx", searchFields);
            var searchIndex = new SearchIndex("serviceorder-sql-idx", searchFields);

            // If we have run the sample before, this index will be populated
            // We can clear the index by deleting it if it exists and creating
            // it again
            CleanupSearchIndexClientResources(indexClient, searchIndex);

            indexClient.CreateOrUpdateIndex(searchIndex);
            //Creating data source

            Console.WriteLine("Creating data source...");

            var dataSource =
                new SearchIndexerDataSourceConnection(
                    "serviceorder-sql-ds",
                    SearchIndexerDataSourceType.AzureSql,
                    azureSQLConnectionStr,
                    new SearchIndexerDataContainer("[ServiceOrder]"));

            indexerClient.CreateOrUpdateDataSourceConnection(dataSource);

            //Creating indexer
            Console.WriteLine("Creating Azure SQL indexer...");

            //var schedule = new IndexingSchedule(TimeSpan.FromDays(1))
            //{
            //    StartTime = DateTimeOffset.Now
            //};

            var parameters = new IndexingParameters()
            {
                BatchSize              = 100,
                MaxFailedItems         = 0,
                MaxFailedItemsPerBatch = 0
            };



            // Indexer declarations require a data source and search index.
            // Common optional properties include a schedule, parameters, and field mappings
            // The field mappings below are redundant due to how the Hotel class is defined, but
            // we included them anyway to show the syntax
            var indexer = new SearchIndexer("serviceorder-sql-idxr", dataSource.Name, searchIndex.Name)
            {
                Description = "Service Order indexer",
                Schedule    = new IndexingSchedule(TimeSpan.FromMinutes(5)),
                Parameters  = parameters,
            };

            indexerClient.CreateOrUpdateIndexerAsync(indexer);

            Console.WriteLine("Running Azure SQL indexer...");

            try
            {
                indexerClient.RunIndexerAsync(indexer.Name);
            }
            catch (CloudException e) when(e.Response.StatusCode == (HttpStatusCode)429)
            {
                Console.WriteLine("Failed to run indexer: {0}", e.Response.Content);
            }

            // Wait 5 seconds for indexing to complete before checking status
            Console.WriteLine("Waiting for indexing...\n");
            System.Threading.Thread.Sleep(5000);
        }
        private void InitializeConcertsIndex(SearchIndexClient serviceClient)
        {
            // Create the index that will contain the searchable data from the concerts.
            var concertsIndex = new SearchIndex(IndexNameConcerts)
            {
                Fields = new[]
                {
                    new SearchField(nameof(Concert.Id), SearchFieldDataType.String)
                    {
                        IsKey        = true,
                        IsSearchable = false
                    },
                    new SearchField(nameof(Concert.Artist), SearchFieldDataType.String)
                    {
                        AnalyzerName = LexicalAnalyzerName.EnMicrosoft,
                        IsSearchable = true,
                    },
                    new SearchField(nameof(Concert.Genre), SearchFieldDataType.String)
                    {
                        AnalyzerName = LexicalAnalyzerName.EnMicrosoft,
                        IsSearchable = true,
                        IsFilterable = true,
                        IsFacetable  = true
                    },
                    new SearchField(nameof(Concert.Location), SearchFieldDataType.String)
                    {
                        AnalyzerName = LexicalAnalyzerName.EnMicrosoft,
                        IsSearchable = true,
                        IsFilterable = true,
                        IsFacetable  = true
                    },
                    new SearchField(nameof(Concert.Title), SearchFieldDataType.String)
                    {
                        AnalyzerName = LexicalAnalyzerName.EnMicrosoft,
                        IsSearchable = true,
                    },
                    new SearchField(nameof(Concert.Description), SearchFieldDataType.String)
                    {
                        AnalyzerName = LexicalAnalyzerName.EnMicrosoft,
                        IsSearchable = true,
                    },
                    new SearchField(nameof(Concert.Price), SearchFieldDataType.Double)
                    {
                        IsSearchable = false,
                        IsFilterable = true,
                        IsFacetable  = true,
                        IsSortable   = true,
                    },
                    new SearchField(nameof(Concert.StartTime), SearchFieldDataType.DateTimeOffset)
                    {
                        IsSearchable = false,
                        IsSortable   = true,
                        IsFilterable = true
                    },
                },
                DefaultScoringProfile = "default-scoring",
            };

            var suggester = new SearchSuggester("default-suggester", new[] { nameof(Concert.Artist), nameof(Concert.Location), nameof(Concert.Title) });

            concertsIndex.Suggesters.Add(suggester);
            concertsIndex.ScoringProfiles.Add(new ScoringProfile("default-scoring")
            {
                // Add a lot of weight to the artist and above average weight to the title.
                TextWeights = new TextWeights(new Dictionary <string, double> {
                    { nameof(Concert.Artist), 2.0 },
                    { nameof(Concert.Title), 1.5 }
                })
            });

            serviceClient.CreateOrUpdateIndex(concertsIndex);

            var searchIndexerClient = new SearchIndexerClient(this.searchServiceUri, this.azureKeyCredential);

            // Create the data source that connects to the SQL Database account containing the consult requests.
            var concertsDataSource = new SearchIndexerDataSourceConnection(IndexNameConcerts, SearchIndexerDataSourceType.AzureSql, this.concertsSqlDatabaseConnectionString, new SearchIndexerDataContainer("Concerts"))
            {
                DataChangeDetectionPolicy = new SqlIntegratedChangeTrackingPolicy()
            };

            searchIndexerClient.CreateOrUpdateDataSourceConnection(concertsDataSource);

            // Create the indexer that will pull the data from the database into the search index.
            var concertsIndexer = new SearchIndexer(name: IndexNameConcerts, dataSourceName: IndexNameConcerts, targetIndexName: IndexNameConcerts)
            {
                Schedule = new IndexingSchedule(TimeSpan.FromMinutes(5))
            };

            searchIndexerClient.CreateOrUpdateIndexer(concertsIndexer);
        }
Beispiel #15
0
        public void CreateIndex <T>()
        {
            string             azureSQLConnectionStr = ConfigurationManager.AppSettings["AzureSqlConnectionString"].ToString();
            Uri                Uri = new Uri(ConfigurationManager.AppSettings["SearchServiceEndPoint"]);
            string             searchServiceKey = ConfigurationManager.AppSettings["SearchServiceAdminApiKey"];
            AzureKeyCredential keyCredential    = new AzureKeyCredential(searchServiceKey);


            SearchIndexClient   indexClient   = new SearchIndexClient(Uri, keyCredential);
            SearchIndexerClient indexerClient = new SearchIndexerClient(Uri, keyCredential);

            Console.WriteLine("Creating index...");
            _logger.LogInformation("Creating index for Orion Customer");
            FieldBuilder fieldBuilder = new FieldBuilder();
            var          searchFields = fieldBuilder.Build(typeof(T));
            var          searchIndex  = new SearchIndex(GetIndexName(HdsConstants.Orion, typeof(T).ToString()), searchFields);

            CleanupSearchIndexClientResources(indexClient, searchIndex);

            indexClient.CreateOrUpdateIndex(searchIndex);


            Console.WriteLine("Creating data source...");
            _logger.LogInformation("Creating data source for Orion Customer");

            var dataSource =
                new SearchIndexerDataSourceConnection(
                    GetDataSourceName(HdsConstants.Orion, typeof(T).ToString()),
                    SearchIndexerDataSourceType.AzureSql,
                    azureSQLConnectionStr,
                    new SearchIndexerDataContainer($"[{GetTableName(typeof(T).ToString())}]"));

            indexerClient.CreateOrUpdateDataSourceConnection(dataSource);

            //Creating indexer
            Console.WriteLine("Creating Azure SQL indexer...");
            _logger.LogInformation("Creating Azure SQL indexer for Orion Customer");

            var schedule = new IndexingSchedule(TimeSpan.FromDays(1))
            {
                StartTime = DateTimeOffset.Now
            };

            var parameters = new IndexingParameters()
            {
                BatchSize              = 100,
                MaxFailedItems         = 0,
                MaxFailedItemsPerBatch = 0
            };

            var indexer = new SearchIndexer(GetIndexerName(HdsConstants.Orion, typeof(T).ToString()), dataSource.Name, searchIndex.Name)
            {
                Description = "Data indexer",
                Schedule    = schedule,
                Parameters  = parameters,
            };

            indexerClient.CreateOrUpdateIndexerAsync(indexer);


            Console.WriteLine("Running Azure SQL indexer...");

            try
            {
                indexerClient.RunIndexerAsync(indexer.Name);
            }
            catch (CloudException e) when(e.Response.StatusCode == (HttpStatusCode)429)
            {
                Console.WriteLine("Failed to run indexer: {0}", e.Response.Content);
                _logger.LogError("Failed to run indexer: {0}", e.Response.Content);
            }
        }
        // This sample shows how ETags work by performing conditional updates and deletes
        // on an Azure Search index.
        static async Task Main(string[] args)
        {
            IConfigurationBuilder builder       = new ConfigurationBuilder().AddJsonFile("appsettings.json");
            IConfigurationRoot    configuration = builder.Build();

            SearchIndexClient indexClient = CreateSearchIndexClient(configuration);

            Console.WriteLine("Deleting index...\n");
            DeleteTestIndexIfExists(indexClient);

            // Every top-level resource in Azure Search has an associated ETag that keeps track of which version
            // of the resource you're working on. When you first create a resource such as an index, its ETag is
            // empty.
            SearchIndex index = DefineTestIndex();

            Console.WriteLine(
                $"Test searchIndex hasn't been created yet, so its ETag should be blank. ETag: '{index.ETag}'");

            // Once the resource exists in Azure Search, its ETag will be populated. Make sure to use the object
            // returned by the SearchIndexClient! Otherwise, you will still have the old object with the
            // blank ETag.
            //Console.WriteLine("Creating index...\n");
            index = indexClient.CreateIndex(index);
            Console.WriteLine($"Test index created; Its ETag should be populated. ETag: '{index.ETag}'");


            // ETags let you do some useful things you couldn't do otherwise. For example, by using an If-Match
            // condition, we can update an index using CreateOrUpdateIndexAsync() and be guaranteed that the update will only
            // succeed if the index already exists.
            index.Fields.Add(new SearchField("name", SearchFieldDataType.String)
            {
                AnalyzerName = LexicalAnalyzerName.EnMicrosoft
            });
            index = indexClient.CreateOrUpdateIndex(index);

            index = await indexClient.CreateOrUpdateIndexAsync(index);

            Console.WriteLine(
                $"Test searchIndex updated; Its ETag should have changed since it was created. ETag: '{index.ETag}'");

            // More importantly, ETags protect you from concurrent updates to the same resource. If another
            // client tries to update the resource, it will fail as long as all clients are using the right
            // access conditions.
            SearchIndex indexForClientUpdate       = index;
            SearchIndex indexForClientUpdateFailed = indexClient.GetIndex("test");

            Console.WriteLine("Simulating concurrent update. To start, both clients see the same ETag.");
            Console.WriteLine($"ClientUpdate ETag: '{indexForClientUpdate.ETag}' ClientUpdateFailed ETag: '{indexForClientUpdateFailed.ETag}'");

            // indexForClientUpdate successfully updates the index.
            indexForClientUpdate.Fields.Add(new SearchField("a", SearchFieldDataType.Int32));
            indexForClientUpdate = indexClient.CreateOrUpdateIndex(indexForClientUpdate);

            Console.WriteLine($"Test index updated by ClientUpdate; ETag: '{indexForClientUpdate.ETag}'");

            // indexForClientUpdateFailed tries to update the index, but fails, thanks to the ETag check.
            try
            {
                indexForClientUpdateFailed.Fields.Add(new SearchField("b", SearchFieldDataType.Boolean));
                indexClient.CreateOrUpdateIndex(indexForClientUpdateFailed);

                Console.WriteLine("Whoops; This shouldn't happen");
                Environment.Exit(1);
            }
            catch (RequestFailedException e) when(e.Status == 400)
            {
                Console.WriteLine("ClientUpdateFailed failed to update the index, as expected.");
            }

            // You can also use access conditions with Delete operations. For example, you can implement an
            // atomic version of the DeleteTestIndexIfExists method from this sample like this:
            Console.WriteLine("Deleting index...\n");
            indexClient.DeleteIndex("test");

            // This is slightly better than using the Exists method since it makes only one round trip to
            // Azure Search instead of potentially two. It also avoids an extra Delete request in cases where
            // the resource is deleted concurrently, but this doesn't matter much since resource deletion in
            // Azure Search is idempotent.

            // And we're done! Bye!
            Console.WriteLine("Complete.  Press any key to end application...\n");
            Console.ReadKey();
        }