升级到 Azure 搜索 .NET SDK 版本 1.1Upgrade to Azure Search .NET SDK version 1.1

如果使用的是版本 1.0.2-preview 或更早版本的 Azure 搜索 .NET SDK,本文有助于升级应用程序,以便使用版本 1.1。If you're using version 1.0.2-preview or older of the Azure Search .NET SDK, this article will help you upgrade your application to use version 1.1.

有关包括示例的 SDK 的更多常规演练,请参阅如何使用 .NET 应用程序中的 Azure 搜索For a more general walkthrough of the SDK including examples, see How to use Azure Search from a .NET Application.

备注

升级到版本 1.1 后,或者已经在使用 1.1 和 2.0 之间的某个版本(含预览版),则应升级到版本 3。Once you upgrade to version 1.1, or if you're already using a version between 1.1 and 2.0-preview inclusive, you should upgrade to version 3. 有关说明,请参阅升级到 Azure 搜索 .NET SDK 版本 3See Upgrading to the Azure Search .NET SDK version 3 for instructions.

首先,按以下方法操作更新 Microsoft.Azure.Search 的 NuGet 引用:使用 NuGet 包管理器控制台,或者在 Visual Studio 中右键单击项目引用,然后选择“管理 NuGet 程序包...”。First, update your NuGet reference for Microsoft.Azure.Search using either the NuGet Package Manager Console or by right-clicking on your project references and selecting "Manage NuGet Packages..." in Visual Studio.

在 NuGet 已下载新的程序包及其依赖项后,请重新生成项目。Once NuGet has downloaded the new packages and their dependencies, rebuild your project.

如果之前使用的是版本 1.0.0-preview、1.0.1-preview 或 1.0.2-preview,生成应该已成功,一切准备就绪!If you were previously using version 1.0.0-preview, 1.0.1-preview, or 1.0.2-preview, the build should succeed and you're ready to go!

如果之前使用的是版本 0.13.0-preview 或更早版本,应该会看到如下所示的生成错误:If you were previously using version 0.13.0-preview or older, you should see build errors like the following:

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?)

下一步是逐个修复生成错误。The next step is to fix the build errors one by one. 大多数修复需要更改 SDK 中已重命名的一些类和方法名称。Most will require changing some class and method names that have been renamed in the SDK. 版本 1.1 中的重大更改列表含有这些名称更改的列表。List of breaking changes in version 1.1 contains a list of these name changes.

如果使用自定义类对文档建模,并且这些类具有不可为 null 的基元类型的属性(例如,C# 中的 intbool),应知道 1.1 版的 SDK 中会有 Bug 修复。If you're using custom classes to model your documents, and those classes have properties of non-nullable primitive types (for example, int or bool in C#), there is a bug fix in the 1.1 version of the SDK of which you should be aware. 有关详细信息,请参阅版本 1.1 中的 Bug 修复See Bug fixes in version 1.1 for more details.

最后,在修复了任何生成错误后,可以对应用程序进行更改,以利用新功能(如果愿意)。Finally, once you've fixed any build errors, you can make changes to your application to take advantage of new functionality if you wish.

版本 1.1 中的重大更改列表List of breaking changes in version 1.1

以下列表按更改会影响应用程序代码的可能性排序。The following list is ordered by the likelihood that the change will affect your application code.

IndexBatch 和 IndexAction 更改IndexBatch and IndexAction changes

IndexBatch.Create 已重命名为 IndexBatch.New,且不再有 params 参数。IndexBatch.Create has been renamed to IndexBatch.New and no longer has a params argument. 可以将 IndexBatch.New 用于混用不同类型操作(合并、删除等)的 Batch。You can use IndexBatch.New for batches that mix different types of actions (merges, deletes, etc.). 此外,还有可用于创建 Batch(其中的所有操作都相同)的新静态方法:DeleteMergeMergeOrUploadUploadIn addition, there are new static methods for creating batches where all the actions are the same: Delete, Merge, MergeOrUpload, and Upload.

IndexAction 不再有公共构造函数,并且其属性现已不可变。IndexAction no longer has public constructors and its properties are now immutable. 应该使用新的静态方法针对不同目的创建操作:DeleteMergeMergeOrUploadUploadYou should use the new static methods for creating actions for different purposes: Delete, Merge, MergeOrUpload, and Upload. IndexAction.Create 已删除。IndexAction.Create has been removed. 如果使用了仅需要一个文档的重载,请务必改为使用 UploadIf you used the overload that takes only a document, make sure to use Upload instead.

示例Example

如果代码如下所示:If your code looks like this:

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

若要修复任何生成错误,可以更改为如下所示的代码:You can change it to this to fix any build errors:

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

如有需要,可以进一步简化为如下所示的代码:If you want, you can further simplify it to this:

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

IndexBatchException 更改IndexBatchException changes

IndexBatchException.IndexResponse 属性已重命名为 IndexingResults,且其类型现为 IList<IndexingResult>The IndexBatchException.IndexResponse property has been renamed to IndexingResults, and its type is now IList<IndexingResult>.

示例Example

如果代码如下所示:If your code looks like this:

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)));
}

若要修复任何生成错误,可以更改为如下所示的代码:You can change it to this to fix any build errors:

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)));
}

操作方法更改Operation method changes

Azure 搜索 .NET SDK 中的每个操作都公开为同步和异步调用方的一组方法重载。Each operation in the Azure Search .NET SDK is exposed as a set of method overloads for synchronous and asynchronous callers. 这些方法重载的签名和分解在版本 1.1 中已更改。The signatures and factoring of these method overloads has changed in version 1.1.

例如,较早版本的 SDK 中的“获取索引统计信息”操作公开以下签名:For example, the "Get Index Statistics" operation in older versions of the SDK exposed these signatures:

IIndexOperations 中:In IIndexOperations:

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

IndexOperationsExtensions 中:In 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);

版本 1.1 中同一操作的方法签名如下所示:The method signatures for the same operation in version 1.1 look like this:

IIndexesOperations 中:In 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));

IndexesOperationsExtensions 中:In 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));

从版本 1.1 开始,Azure 搜索 .NET SDK 以不同方式组织操作方法:Starting with version 1.1, the Azure Search .NET SDK organizes operation methods differently:

  • 可选参数现已建模为默认参数,而不是附加的方法重载。Optional parameters are now modeled as default parameters rather than additional method overloads. 这有时可显著减少方法重载的数目。This reduces the number of method overloads, sometimes dramatically.
  • 扩展方法现在对调用方隐藏了许多与 HTTP 无关的细节。The extension methods now hide a lot of the extraneous details of HTTP from the caller. 例如,较早版本的 SDK 返回响应对象时带有 HTTP 状态代码,通常不需要检查这些状态代码,因为操作方法会为指示错误的任何状态代码引发 CloudExceptionFor example, older versions of the SDK returned a response object with an HTTP status code, which you often didn't need to check because operation methods throw CloudException for any status code that indicates an error. 新的扩展方法只返回模型对象,使你无需在代码中对其进行解包。The new extension methods just return model objects, saving you the trouble of having to unwrap them in your code.
  • 核心接口现在反而公开了允许在 HTTP 级别进行更多控制的方法(如果需要)。Conversely, the core interfaces now expose methods that give you more control at the HTTP level if you need it. 现在可以传入要包括在请求中的自定义 HTTP 标头,并且新的 AzureOperationResponse<T> 返回类型使你可以直接访问操作的 HttpRequestMessageHttpResponseMessageYou can now pass in custom HTTP headers to be included in requests, and the new AzureOperationResponse<T> return type gives you direct access to the HttpRequestMessage and HttpResponseMessage for the operation. AzureOperationResponseMicrosoft.Rest.Azure 命名空间中定义,替换 Hyak.Common.OperationResponseAzureOperationResponse is defined in the Microsoft.Rest.Azure namespace and replaces Hyak.Common.OperationResponse.

ScoringParameters 更改ScoringParameters changes

名为 ScoringParameter 的新类已添加到最新的 SDK 中,使向搜索查询中的计分配置文件提供参数更为容易。A new class named ScoringParameter has been added in the latest SDK to make it easier to provide parameters to scoring profiles in a search query. 之前,SearchParameters 类的 ScoringProfiles 属性以 IList<string> 形式键入;现在它以 IList<ScoringParameter> 形式键入。Previously the ScoringProfiles property of the SearchParameters class was typed as IList<string>; Now it is typed as IList<ScoringParameter>.

示例Example

如果代码如下所示:If your code looks like this:

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

若要修复任何生成错误,可以更改为如下所示的代码:You can change it to this to fix any build errors:

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))
    };

模型类更改Model class changes

由于操作方法更改中描述的签名更改,Microsoft.Azure.Search.Models 命名空间中的许多类已重命名或已删除。Due to the signature changes described in Operation method changes, many classes in the Microsoft.Azure.Search.Models namespace have been renamed or removed. 例如:For example:

  • IndexDefinitionResponse 已替换为 AzureOperationResponse<Index>IndexDefinitionResponse has been replaced by AzureOperationResponse<Index>
  • DocumentSearchResponse 已重名为 DocumentSearchResultDocumentSearchResponse has been renamed to DocumentSearchResult
  • IndexResult 已重名为 IndexingResultIndexResult has been renamed to IndexingResult
  • Documents.Count() 现在返回带有文档计数的 long,而不是 DocumentCountResponseDocuments.Count() now returns a long with the document count instead of a DocumentCountResponse
  • IndexGetStatisticsResponse 已重名为 IndexGetStatisticsResultIndexGetStatisticsResponse has been renamed to IndexGetStatisticsResult
  • IndexListResponse 已重名为 IndexListResultIndexListResponse has been renamed to IndexListResult

总之,仅用于包裹模型对象的现有 OperationResponse 派生类已删除。To summarize, OperationResponse-derived classes that existed only to wrap a model object have been removed. 其余类已将其后缀从 Response 更改为 ResultThe remaining classes have had their suffix changed from Response to Result.

示例Example

如果代码如下所示:If your code looks like this:

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;

若要修复任何生成错误,可以更改为如下所示的代码:You can change it to this to fix any build errors:

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;

响应类和 IEnumerableResponse classes and IEnumerable

可能影响代码的其他更改是:保留集合的响应类不再实现 IEnumerable<T>An additional change that may affect your code is that response classes that hold collections no longer implement IEnumerable<T>. 相反,可以直接访问集合属性。Instead, you can access the collection property directly. 例如,如果代码如下所示:For example, if your code looks like this:

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

若要修复任何生成错误,可以更改为如下所示的代码:You can change it to this to fix any build errors:

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

Web 应用程序的特例Special case for web applications

如果有一个直接序列化 DocumentSearchResponse 以向浏览器发送搜索结果的 Web 应用程序,将需要更改代码,否则结果将不会正确序列化。If you have a web application that serializes DocumentSearchResponse directly to send search results to the browser, you will need to change your code or the results will not serialize correctly. 例如,如果代码如下所示:For example, if your code looks like this:

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 属性来更改代码,以修复结果呈现:You can change it by getting the .Results property of the search response to fix search result rendering:

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
    };
}

必须自己在代码中查找此类情况;编译器不会警告你,因为 JsonResult.Data 属于类型 objectYou will have to look for such cases in your code yourself; The compiler will not warn you because JsonResult.Data is of type object.

CloudException 更改CloudException changes

CloudException 类已从 Hyak.Common 命名空间移动到 Microsoft.Rest.Azure 命名空间。The CloudException class has moved from the Hyak.Common namespace to the Microsoft.Rest.Azure namespace. 此外,其 Error 属性已重名为 BodyAlso, its Error property has been renamed to Body.

SearchServiceClient 和 SearchIndexClient 更改SearchServiceClient and SearchIndexClient changes

Credentials 属性的类型已从 SearchCredentials 更改为其基类(即 ServiceClientCredentials)。The type of the Credentials property has changed from SearchCredentials to its base class, ServiceClientCredentials. 如果需要访问 SearchIndexClientSearchServiceClientSearchCredentials,请使用新的 SearchCredentials 属性。If you need to access the SearchCredentials of a SearchIndexClient or SearchServiceClient, please use the new SearchCredentials property.

在早期版本的 SDK 中,SearchServiceClientSearchIndexClient 具有需要 HttpClient 参数的构造函数。In older versions of the SDK, SearchServiceClient and SearchIndexClient had constructors that took an HttpClient parameter. 这些已替换为需要 HttpClientHandler 和一个 DelegatingHandler 对象数组的构造函数。These have been replaced with constructors that take an HttpClientHandler and an array of DelegatingHandler objects. 这使得必要时安装用于预处理 HTTP 请求的自定义处理程序更为容易。This makes it easier to install custom handlers to pre-process HTTP requests if necessary.

最后,需要 UriSearchCredentials 的构造函数已更改。Finally, the constructors that took a Uri and SearchCredentials have changed. 例如,如果代码如下所示:For example, if you have code that looks like this:

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

若要修复任何生成错误,可以更改为如下所示的代码:You can change it to this to fix any build errors:

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

另请注意,凭据参数的类型已更改为 ServiceClientCredentialsAlso note that the type of the credentials parameter has changed to ServiceClientCredentials. 由于 SearchCredentials 派生自 ServiceClientCredentials,所以这不太可能影响代码。This is unlikely to affect your code since SearchCredentials is derived from ServiceClientCredentials.

传递请求 IDPassing a request ID

在早期版本的 SDK 中,可以设置 SearchServiceClientSearchIndexClient 上的请求 ID,它将包含在对 REST API 的每个请求中。In older versions of the SDK, you could set a request ID on the SearchServiceClient or SearchIndexClient and it would be included in every request to the REST API. 如果需要与支持人员联系,这对于解决搜索服务的问题非常有用。This is useful for troubleshooting issues with your search service if you need to contact support. 不过,为每个操作设置唯一请求 ID 更加有用,而不是将同一 ID 用于所有操作。However, it is more useful to set a unique request ID for every operation rather than to use the same ID for all operations. 出于此原因,SearchServiceClientSearchIndexClientSetClientRequestId 方法已删除。For this reason, the SetClientRequestId methods of SearchServiceClient and SearchIndexClient have been removed. 相反,可以通过可选参数 SearchRequestOptions 将请求 ID 传递给每个操作方法。Instead, you can pass a request ID to each operation method via the optional SearchRequestOptions parameter.

备注

在将来版本的 SDK 中,我们会添加一个新机制,用于在客户端对象上全局设置请求 ID,这与其他 Azure SDK 使用的方法一致。In a future release of the SDK, we will add a new mechanism for setting a request ID globally on the client objects that is consistent with the approach used by other Azure SDKs.

示例Example

如果代码如下所示:If you have code that looks like this:

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

若要修复任何生成错误,可以更改为如下所示的代码:You can change it to this to fix any build errors:

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

接口名称更改Interface name changes

操作组接口名称已全部更改,与其相应的属性名称保持一致:The operation group interface names have all changed to be consistent with their corresponding property names:

  • ISearchServiceClient.Indexes 的类型已从 IIndexOperations 更改为 IIndexesOperationsThe type of ISearchServiceClient.Indexes has been renamed from IIndexOperations to IIndexesOperations.
  • ISearchServiceClient.Indexers 的类型已从 IIndexerOperations 更改为 IIndexersOperationsThe type of ISearchServiceClient.Indexers has been renamed from IIndexerOperations to IIndexersOperations.
  • ISearchServiceClient.DataSources 的类型已从 IDataSourceOperations 更改为 IDataSourcesOperationsThe type of ISearchServiceClient.DataSources has been renamed from IDataSourceOperations to IDataSourcesOperations.
  • ISearchIndexClient.Documents 的类型已从 IDocumentOperations 更改为 IDocumentsOperationsThe type of ISearchIndexClient.Documents has been renamed from IDocumentOperations to IDocumentsOperations.

此更改不太可能影响代码,除非出于测试目的创建了这些接口的模拟。This change is unlikely to affect your code unless you created mocks of these interfaces for test purposes.

版本 1.1 中的 Bug 修复Bug fixes in version 1.1

与自定义模型类的序列化有关的早期版本的 Azure 搜索 .NET SDK 中存在 Bug。There was a bug in older versions of the Azure Search .NET SDK relating to serialization of custom model classes. 如果使用不可为 null 的值类型的属性创建了自定义模型类,可能会出现 Bug。The bug could occur if you created a custom model class with a property of a non-nullable value type.

重现步骤Steps to reproduce

使用不可为 null 的值类型的属性创建自定义模型类。Create a custom model class with a property of non-nullable value type. 例如,添加类型为 int(而不是 int?)的公共 UnitCount 属性。For example, add a public UnitCount property of type int instead of int?.

如果使用该类型的默认值(例如,int 的 0)对文档编制索引,该字段在 Azure 搜索将为 null。If you index a document with the default value of that type (for example, 0 for int), the field will be null in Azure Search. 如果随后搜索该文档,Search 调用会引发 JsonSerializationException,声称无法将 null 转换为 intIf you subsequently search for that document, the Search call will throw JsonSerializationException complaining that it can't convert null to int.

此外,筛选器可能不会按预期工作,因为 null 已写入索引,而不是预期值。Also, filters may not work as expected since null was written to the index instead of the intended value.

修复详细信息Fix details

我们修复了版本 1.1 的 SDK 中存在的此问题。We have fixed this issue in version 1.1 of the SDK. 现在,如果模型类如下所示:Now, if you have a model class like this:

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

    public int IntValue { get; set; }
}

IntValue 设置为 0,该值现在线路上正确序列化为 0,并在索引中存储为 0。and you set IntValue to 0, that value is now correctly serialized as 0 on the wire and stored as 0 in the index. 往返过程也按预期工作。Round tripping also works as expected.

使用此方法时有一个潜在的问题需要注意:如果将模型类型与不可为 null 的属性一起使用,必须保证索引中的所有文档的对应字段都不包含 null 值。There is one potential issue to be aware of with this approach: If you use a model type with a non-nullable property, you have to guarantee that no documents in your index contain a null value for the corresponding field. 该 SDK 和 Azure 搜索 REST API 都不会帮助强制实施此检查。Neither the SDK nor the Azure Search REST API will help you to enforce this.

这不只是假想的问题:假设将新字段添加到 Edm.Int32类型的现有索引。This is not just a hypothetical concern: Imagine a scenario where you add a new field to an existing index that is of type Edm.Int32. 更新索引定义后,所有文档的该新字段都具有 null 值(因为 Azure 搜索中的所有类型都可以为 null)。After updating the index definition, all documents will have a null value for that new field (since all types are nullable in Azure Search). 如果随后使用该字段具有不可为 null int 属性的模型类,则在尝试检索文档时会获得如下所示的 JsonSerializationExceptionIf you then use a model class with a non-nullable int property for that field, you will get a JsonSerializationException like this when trying to retrieve documents:

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

由于此原因,最佳做法仍建议在模型类中使用可以为 null 的类型。For this reason, we still recommend that you use nullable types in your model classes as a best practice.

有关此 Bug 和修复的更多详细信息,请参阅 GitHub 上的此问题For more details on this bug and the fix, please see this issue on GitHub.