Esempio n. 1
0
        /// <summary>
        /// Get a function to access the key field of a search document.
        /// </summary>
        /// <param name="async">Whether to run sync or async.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A Task representing the operation.</returns>
        private async Task GetKeyFieldAccessorAsync(bool async, CancellationToken cancellationToken)
        {
            // Case 1: The user provided an explicit accessor and we're done
            if (KeyFieldAccessor != null)
            {
                return;
            }

            // Case 2: Infer the accessor from FieldBuilder
            try
            {
                FieldBuilder builder = new FieldBuilder {
                    Serializer = SearchClient.Serializer
                };
                IDictionary <string, SearchField>  fields   = builder.BuildMapping(typeof(T));
                KeyValuePair <string, SearchField> keyField = fields.FirstOrDefault(pair => pair.Value.IsKey == true);
                if (!keyField.Equals(default(KeyValuePair <string, SearchField>)))
                {
                    KeyFieldAccessor = CompileAccessor(keyField.Key);
                    return;
                }
            }
            catch
            {
                // Ignore any errors because this type might not have been
                // designed with FieldBuilder in mind
            }

            // Case 3: Fetch the index to find the key
            Exception failure = null;

            try
            {
                // Call the service to find the name of the key
                SearchIndexClient indexClient = SearchClient.GetSearchIndexClient();
                SearchIndex       index       = async ?
                                                await indexClient.GetIndexAsync(IndexName, cancellationToken).ConfigureAwait(false) :
                                                indexClient.GetIndex(IndexName, cancellationToken);

                SearchField keyField = index.Fields.Single(f => f.IsKey == true);
                string      key      = keyField.Name;

                if (typeof(T).IsAssignableFrom(typeof(SearchDocument)))
                {
                    // Case 3a: If it's a dynamic SearchDocument, lookup
                    // the name of the key in the dictionary
                    KeyFieldAccessor = (T doc) => (doc as SearchDocument)?.GetString(key);
                    return;
                }
                else
                {
                    // Case 3b: We'll see if there's a property with the
                    // same name and use that as the accessor
                    if (typeof(T).GetProperty(key) != null ||
                        typeof(T).GetField(key) != null)
                    {
                        KeyFieldAccessor = CompileAccessor(key);
                        return;
                    }
                }
            }
            catch (Exception ex)
            {
                // We'll provide any exceptions as a hint because it could
                // be something like using the wrong API Key type when
                // moving from SearchClient up to SearchIndexClient that
                // potentially could be addressed if the user really wanted
                failure = ex;
            }

            // Case 4: Throw and tell the user to provide an explicit accessor.
            throw new InvalidOperationException(
                      $"Failed to discover the Key field of document type {typeof(T).Name} for Azure Cognitive Search index {IndexName}.  " +
                      $"Please set {typeof(SearchIndexingBufferedSenderOptions<T>).Name}.{nameof(SearchIndexingBufferedSenderOptions<T>.KeyFieldAccessor)} explicitly.",
                      failure);