Partilhar via


Upgrade para Azure Search .NET SDK versão 1.1

Se estiver a utilizar a versão 1.0.2 pré-visualização ou mais antiga do Azure Search .NET SDK, este artigo irá ajudá-lo a atualizar a sua aplicação para utilizar a versão 1.1.

Para uma passagem mais geral do SDK, incluindo exemplos, consulte Como utilizar a Azure Search a partir de uma aplicação .NET.

Nota

Uma vez atualizado para a versão 1.1, ou se já estiver a utilizar uma versão entre 1.1 e 2.0 inclusive, deverá atualizar para a versão 3. Consulte a atualização para a versão 3 da Azure Search .NET SDK para obter instruções.

Em primeiro lugar, atualize a sua referência NuGet para Microsoft.Azure.Search utilizar a Consola nuGet Gestor de Pacotes ou clicando à direita nas referências do seu projeto e selecionando "Gerir pacotes nuget..." em Visual Studio.

Assim que o NuGet tiver descarregado os novos pacotes e as suas dependências, reconstrua o seu projeto.

Se já estava a utilizar a versão 1.0.0 pré-visualização, 1.0.1 pré-visualização ou 1.0.2 pré-visualização, a construção deverá ter sucesso e está pronta para partir!

Se já usou a versão 0.13.0 ou mais antiga, deverá ver erros de construção como o seguinte:

Program.cs(137,56,137,62): error CS0117: 'Microsoft.Azure.Search.Models.IndexBatch' does not contain a definition for 'Create'
Program.cs(137,99,137,105): error CS0117: 'Microsoft.Azure.Search.Models.IndexAction' does not contain a definition for 'Create'
Program.cs(146,41,146,54): error CS1061: 'Microsoft.Azure.Search.IndexBatchException' does not contain a definition for 'IndexResponse' and no extension method 'IndexResponse' accepting a first argument of type 'Microsoft.Azure.Search.IndexBatchException' could be found (are you missing a using directive or an assembly reference?)
Program.cs(163,13,163,42): error CS0246: The type or namespace name 'DocumentSearchResponse' could not be found (are you missing a using directive or an assembly reference?)

O próximo passo é corrigir os erros de construção um a um. A maioria requer alterações de nomes de classe e métodos que foram renomeados no SDK. A lista de alterações de rutura na versão 1.1 contém uma lista destas alterações de nome.

Se estiver a usar aulas personalizadas para modelo seus documentos, e essas classes tiverem propriedades de tipos primitivos não nulos (por exemplo, int ou bool em C#), existe uma correção de bugs na versão 1.1 do SDK de que deve estar ciente. Consulte as correções do Bug na versão 1.1 para obter mais detalhes.

Finalmente, uma vez corrigido quaisquer erros de construção, pode escoar alterações na sua aplicação para tirar partido de novas funcionalidades, se desejar.

Lista de alterações na versão 1.1

A lista a seguir é ordenada pela probabilidade de a alteração afetar o seu código de aplicação.

Alterações de IndexBatch e IndexAction

IndexBatch.Create foi renomeado e IndexBatch.New já não tem argumentos params . Pode utilizar IndexBatch.New para lotes que misturam diferentes tipos de ações (fusões, eliminações, etc.). Além disso, existem novos métodos estáticos para a criação de lotes onde todas as ações são as mesmas: Delete, Merge, e MergeOrUploadUpload.

IndexAction já não tem construtores públicos e as suas propriedades são agora imutáveis. Deve utilizar os novos métodos estáticos para criar ações para diferentes finalidades: Delete, Mergee MergeOrUploadUpload. IndexAction.Create foi removido. Se utilizar a sobrecarga que leva apenas um documento, certifique-se de que utiliza Upload .

Exemplo

Se o seu código se parece com isto:

var batch = IndexBatch.Create(documents.Select(doc => IndexAction.Create(doc)));
indexClient.Documents.Index(batch);

Pode alterá-lo para isto para corrigir quaisquer erros de construção:

var batch = IndexBatch.New(documents.Select(doc => IndexAction.Upload(doc)));
indexClient.Documents.Index(batch);

Se quiser, pode simplificar ainda mais isto:

var batch = IndexBatch.Upload(documents);
indexClient.Documents.Index(batch);

Alterações no IndexBatchException

A IndexBatchException.IndexResponse propriedade foi renomeada para IndexingResults, e o seu tipo é agora IList<IndexingResult>.

Exemplo

Se o seu código se parece com isto:

catch (IndexBatchException e)
{
    Console.WriteLine(
        "Failed to index some of the documents: {0}",
        String.Join(", ", e.IndexResponse.Results.Where(r => !r.Succeeded).Select(r => r.Key)));
}

Pode alterá-lo para isto para corrigir quaisquer erros de construção:

catch (IndexBatchException e)
{
    Console.WriteLine(
        "Failed to index some of the documents: {0}",
        String.Join(", ", e.IndexingResults.Where(r => !r.Succeeded).Select(r => r.Key)));
}

Alterações do método de operação

Cada operação no Azure Search .NET SDK é exposta como um conjunto de sobrecargas de método para chamadas sincronizadas e assíncronas. As assinaturas e o factoring destas sobrecargas de métodos mudaram na versão 1.1.

Por exemplo, a operação "Obter Estatísticas de Índice" em versões mais antigas do SDK expôs estas assinaturas:

Em IIndexOperations:

// Asynchronous operation with all parameters
Task<IndexGetStatisticsResponse> GetStatisticsAsync(
    string indexName,
    CancellationToken cancellationToken);

Em IndexOperationsExtensions:

// Asynchronous operation with only required parameters
public static Task<IndexGetStatisticsResponse> GetStatisticsAsync(
    this IIndexOperations operations,
    string indexName);

// Synchronous operation with only required parameters
public static IndexGetStatisticsResponse GetStatistics(
    this IIndexOperations operations,
    string indexName);

As assinaturas-método para a mesma operação na versão 1.1 são assim:

Em IIndexesOperations:

// Asynchronous operation with lower-level HTTP features exposed
Task<AzureOperationResponse<IndexGetStatisticsResult>> GetStatisticsWithHttpMessagesAsync(
    string indexName,
    SearchRequestOptions searchRequestOptions = default(SearchRequestOptions),
    Dictionary<string, List<string>> customHeaders = null,
    CancellationToken cancellationToken = default(CancellationToken));

Em IndexesOperationsExtensions:

// Simplified asynchronous operation
public static Task<IndexGetStatisticsResult> GetStatisticsAsync(
    this IIndexesOperations operations,
    string indexName,
    SearchRequestOptions searchRequestOptions = default(SearchRequestOptions),
    CancellationToken cancellationToken = default(CancellationToken));

// Simplified synchronous operation
public static IndexGetStatisticsResult GetStatistics(
    this IIndexesOperations operations,
    string indexName,
    SearchRequestOptions searchRequestOptions = default(SearchRequestOptions));

Começando pela versão 1.1, o Azure Search .NET SDK organiza métodos de funcionamento de forma diferente:

  • Os parâmetros opcionais são agora modelados como parâmetros padrão em vez de sobrecargas adicionais do método. Isto reduz o número de sobrecargas de métodos, por vezes dramaticamente.
  • Os métodos de extensão agora escondem muitos dos detalhes extra-estóceias de HTTP do chamador. Por exemplo, versões mais antigas do SDK devolveram um objeto de resposta com um código de estado HTTP, que muitas vezes não precisava de verificar porque os métodos de funcionamento lançam CloudException para qualquer código de estado que indique um erro. Os novos métodos de extensão apenas devolvem modelo objetos, poupando-lhe o trabalho de ter que desembrulhá-los no seu código.
  • Inversamente, as interfaces centrais agora expõem métodos que lhe dão mais controlo ao nível HTTP se precisar. Agora pode passar em cabeçalhos HTTP personalizados para serem incluídos em pedidos, e o novo AzureOperationResponse<T> tipo de devolução dá-lhe acesso direto ao HttpRequestMessage e HttpResponseMessage para a operação. AzureOperationResponse é definido no espaço de Microsoft.Rest.Azure nome e substitui Hyak.Common.OperationResponse.

Alterações de Pontuação Parametros

Uma nova classe nomeada ScoringParameter foi adicionada no mais recente SDK para facilitar a disponibilização de parâmetros para marcar perfis numa consulta de pesquisa. Anteriormente, a ScoringProfiles propriedade da SearchParameters classe era dactilografada como IList<string>; Agora é dactilografado como IList<ScoringParameter>.

Exemplo

Se o seu código se parece com isto:

var sp = new SearchParameters();
sp.ScoringProfile = "jobsScoringFeatured";      // Use a scoring profile
sp.ScoringParameters = new[] { "featuredParam-featured", "mapCenterParam-" + lon + "," + lat };

Pode alterá-lo para isto para corrigir quaisquer erros de construção:

var sp = new SearchParameters();
sp.ScoringProfile = "jobsScoringFeatured";      // Use a scoring profile
sp.ScoringParameters =
    new[]
    {
        new ScoringParameter("featuredParam", new[] { "featured" }),
        new ScoringParameter("mapCenterParam", GeographyPoint.Create(lat, lon))
    };

Mudanças de classe de modelo

Devido às alterações de assinatura descritas nas alterações do método de Operação, muitas classes no espaço de Microsoft.Azure.Search.Models nome foram renomeadas ou removidas. Por exemplo:

  • IndexDefinitionResponse foi substituído por AzureOperationResponse<Index>
  • DocumentSearchResponse mudou de nome para DocumentSearchResult
  • IndexResult mudou de nome para IndexingResult
  • Documents.Count() agora devolve um long com a contagem de documentos em vez de um DocumentCountResponse
  • IndexGetStatisticsResponse mudou de nome para IndexGetStatisticsResult
  • IndexListResponse mudou de nome para IndexListResult

Para resumir, OperationResponseclasses derivadas que existiam apenas para embrulhar um objeto modelo foram removidas. As restantes classes mudaram de sufixo Response para Result.

Exemplo

Se o seu código se parece com isto:

IndexerGetStatusResponse statusResponse = null;

try
{
    statusResponse = _searchClient.Indexers.GetStatus(indexer.Name);
}
catch (Exception ex)
{
    Console.WriteLine("Error polling for indexer status: {0}", ex.Message);
    return;
}

IndexerExecutionResult lastResult = statusResponse.ExecutionInfo.LastResult;

Pode alterá-lo para isto para corrigir quaisquer erros de construção:

IndexerExecutionInfo status = null;

try
{
    status = _searchClient.Indexers.GetStatus(indexer.Name);
}
catch (Exception ex)
{
    Console.WriteLine("Error polling for indexer status: {0}", ex.Message);
    return;
}

IndexerExecutionResult lastResult = status.LastResult;

Aulas de resposta e IEnumerable

Uma alteração adicional que pode afetar o seu código é que as classes de resposta que detêm coleções já não implementam IEnumerable<T>. Em vez disso, pode aceder diretamente à propriedade de recolha. Por exemplo, se o seu código se parece com isto:

DocumentSearchResponse<Hotel> response = indexClient.Documents.Search<Hotel>(searchText, sp);
foreach (SearchResult<Hotel> result in response)
{
    Console.WriteLine(result.Document);
}

Pode alterá-lo para isto para corrigir quaisquer erros de construção:

DocumentSearchResult<Hotel> response = indexClient.Documents.Search<Hotel>(searchText, sp);
foreach (SearchResult<Hotel> result in response.Results)
{
    Console.WriteLine(result.Document);
}

Caso especial para aplicações web

Se tiver uma aplicação web que serialize diretamente para enviar resultados DocumentSearchResponse de pesquisa para o navegador, terá de alterar o seu código ou os resultados não serão serializáveis corretamente. Por exemplo, se o seu código se parece com isto:

public ActionResult Search(string q = "")
{
    // If blank search, assume they want to search everything
    if (string.IsNullOrWhiteSpace(q))
        q = "*";

    return new JsonResult
    {
        JsonRequestBehavior = JsonRequestBehavior.AllowGet,
        Data = _featuresSearch.Search(q)
    };
}

Pode alterá-la obtenda através da obtenção .Results da propriedade da resposta de pesquisa para corrigir a renderização do resultado da pesquisa:

public ActionResult Search(string q = "")
{
    // If blank search, assume they want to search everything
    if (string.IsNullOrWhiteSpace(q))
        q = "*";

    return new JsonResult
    {
        JsonRequestBehavior = JsonRequestBehavior.AllowGet,
        Data = _featuresSearch.Search(q).Results
    };
}

Você mesmo terá de procurar tais casos no seu código; O compilador não o avisa porque JsonResult.Data é do tipo object.

Alterações cloudException

A CloudException classe passou do espaço para Hyak.Common o espaço de Microsoft.Rest.Azure nomes. Além disso, a sua Error propriedade foi renomeada para Body.

Alterações do SearchServiceClient e SearchIndexClient

O tipo de Credentials propriedade mudou de SearchCredentials classe base, ServiceClientCredentials. Se precisar de aceder ao SearchCredentials ou SearchIndexClientSearchServiceClient, por favor, use o novo SearchCredentials imóvel.

Em versões mais antigas do SDK, SearchServiceClient e SearchIndexClient tinha construtores que tomavam um HttpClient parâmetro. Estes foram substituídos por construtores que tomam uma HttpClientHandler e uma variedade de DelegatingHandler objetos. Isto facilita a instalação de manipuladores personalizados para pré-processar pedidos HTTP, se necessário.

Finalmente, os construtores que tomaram um Uri e SearchCredentials mudaram. Por exemplo, se tiver um código que se pareça com este:

var client =
    new SearchServiceClient(
        new SearchCredentials("abc123"),
        new Uri("http://myservice.search.windows.net"));

Pode alterá-lo para isto para corrigir quaisquer erros de construção:

var client =
    new SearchServiceClient(
        new Uri("http://myservice.search.windows.net"),
        new SearchCredentials("abc123"));

Note também que o tipo de parâmetro de credenciais mudou para ServiceClientCredentials. É pouco provável que isto afete o seu código, uma vez SearchCredentials que é derivado de ServiceClientCredentials.

Passando uma ID de pedido

Em versões mais antigas do SDK, pode definir um ID de pedido no SearchServiceClient ou SearchIndexClient e seria incluído em todos os pedidos à API REST. Isto é útil para resolver problemas com o seu serviço de pesquisa se precisar de contactar o suporte. No entanto, é mais útil definir um ID de pedido único para cada operação do que usar o mesmo ID para todas as operações. Por esta razão, os SetClientRequestId métodos de SearchServiceClient e SearchIndexClient foram removidos. Em vez disso, pode passar um ID de pedido a cada método de operação através do parâmetro opcional SearchRequestOptions .

Nota

Numa futura versão do SDK, adicionaremos um novo mecanismo para definir um ID de pedido globalmente nos objetos do cliente que é consistente com a abordagem usada por outros SDKs Azure.

Exemplo

Se tiver um código que se pareça com este:

client.SetClientRequestId(Guid.NewGuid());
...
long count = client.Documents.Count();

Pode alterá-lo para isto para corrigir quaisquer erros de construção:

long count = client.Documents.Count(new SearchRequestOptions(requestId: Guid.NewGuid()));

Alterações no nome da interface

Os nomes da interface do grupo de operação foram alterados para serem consistentes com os respetivos nomes de propriedade:

  • O tipo de ISearchServiceClient.Indexes foi renomeado deIIndexOperations.IIndexesOperations
  • O tipo de ISearchServiceClient.Indexers foi renomeado deIIndexerOperations.IIndexersOperations
  • O tipo de ISearchServiceClient.DataSources foi renomeado deIDataSourceOperations.IDataSourcesOperations
  • O tipo de ISearchIndexClient.Documents foi renomeado deIDocumentOperations.IDocumentsOperations

Esta alteração é improvável que afete o seu código a menos que tenha criado simulações destas interfaces para fins de teste.

Correções de bugs na versão 1.1

Houve um bug em versões mais antigas do Azure Search .NET SDK relacionado com a serialização de classes modelo personalizadas. O bug pode ocorrer se criar uma classe modelo personalizada com uma propriedade de um tipo de valor não anulado.

Passos para reproduzir

Crie uma classe modelo personalizada com uma propriedade de valor não anulado. Por exemplo, adicione uma propriedade pública UnitCount do tipo int em vez de int?.

Se indexar um documento com o valor predefinido desse tipo (por exemplo, 0 para int), o campo será nulo na Pesquisa de Azure. Se posteriormente pesquisar esse documento, a Search chamada irá lançar JsonSerializationException reclamando que não pode converter null para int.

Além disso, os filtros podem não funcionar como esperado, uma vez que o nulo foi escrito ao índice em vez do valor pretendido.

Corrigir detalhes

Corrigimos esta questão na versão 1.1 do SDK. Agora, se tiver uma aula modelo como esta:

public class Model
{
    public string Key { get; set; }

    public int IntValue { get; set; }
}

e definiu IntValue para 0, esse valor é agora corretamente serializado como 0 no fio e armazenado como 0 no índice. Tropeçar em volta também funciona como esperado.

Há um problema potencial a ter em conta com esta abordagem: Se utilizar um tipo modelo com uma propriedade não au nuptilável, tem de garantir que nenhum documento no seu índice contenha um valor nulo para o campo correspondente. Nem o SDK nem a Azure Search REST API o ajudarão a impor isto.

Esta não é apenas uma preocupação hipotética: imagine um cenário onde adiciona um novo campo a um índice existente do tipo Edm.Int32. Depois de atualizar a definição do índice, todos os documentos terão um valor nulo para esse campo novo (uma vez que todos os tipos são anuláveis na Azure Search). Se, em seguida, utilizar uma classe de modelo com uma propriedade int não anulável para esse campo, obterá uma JsonSerializationException assim ao tentar obter documentos:

Error converting value {null} to type 'System.Int32'. Path 'IntValue'.

Por esta razão, recomendamos ainda que utilize tipos nulos nas suas aulas de modelo como uma boa prática.

Para mais detalhes sobre este bug e a correção, consulte este assunto na GitHub.