如果使用的是版本 1.0.2-preview 或更高版本的 Azure 搜索 .NET SDK,本文将帮助你升级应用程序以使用版本 1.1。
要获得有关 SDK 的更全面的演练,包括示例,可以参阅 #B0 从 .NET 应用程序中使用 Azure 搜索的方法 #A1。
注释
升级到版本 1.1 或已使用版本 1.1 到 2.0-preview(含 2.0)后,应升级到版本 3。 有关说明 ,请参阅升级到 Azure 搜索 .NET SDK 版本 3 。
首先,在 Visual Studio 中,更新项目中的 Microsoft.Azure.Search 的 NuGet 引用,可以通过使用 NuGet 包管理器控制台,或者右键单击项目中的引用并选择“管理 NuGet 包...” 。
NuGet 下载新包及其依赖项后,请重新生成项目。
如果以前使用的是版本 1.0.0-preview、1.0.1-preview 或 1.0.2-preview,则生成应成功,并且可以开始使用了!
如果以前使用的是版本 0.13.0-preview 或更早版本,应会看到生成错误,如下所示:
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?)
下一步是逐个修复生成错误。 大多数都需要更改已在 SDK 中重命名的某些类和方法名称。 版本 1.1 中的重大变更列表 包含这些名称更改的列表。
如果您使用自定义类来对文档进行建模,并且这些类具有不可为 null 的原始类型属性(例如,在 C# 中的 int 或 bool),那么请注意在 SDK 的 1.1 版本中修复了一个错误。 有关更多详细信息,请参阅 版本 1.1 中的 Bug 修复 。
最后,修复任何生成错误后,可以更改应用程序以利用新功能(如果需要)。
版本 1.1 中的重大变更列表
以下列表按更改可能会影响应用程序代码的可能性进行排序。
IndexBatch 和 IndexAction 更改
IndexBatch.Create 已重命名为 IndexBatch.New 不再具有 params 参数。 您可以将 IndexBatch.New 用于混合不同类型操作(合并、删除等)的批次。 此外,还有一些用于创建批处理的新静态方法,其中所有作都相同: Delete、 Merge、 MergeOrUpload和 Upload。
IndexAction 不再具有公共构造函数,其属性现在不可变。 您应该使用新的静态方法来创建用于不同目的的动作:Delete、Merge、MergeOrUpload 和 Upload。
IndexAction.Create 已删除。 如果你使用了仅接受文档作为参数的重载,请确保改为使用 Upload。
示例:
如果代码如下所示:
var batch = IndexBatch.Create(documents.Select(doc => IndexAction.Create(doc)));
indexClient.Documents.Index(batch);
可以将其更改为这样以修复任何构建错误:
var batch = IndexBatch.New(documents.Select(doc => IndexAction.Upload(doc)));
indexClient.Documents.Index(batch);
如果愿意,您可以进一步简化为这样:
var batch = IndexBatch.Upload(documents);
indexClient.Documents.Index(batch);
IndexBatchException 的更改
该 IndexBatchException.IndexResponse 属性已重命名为 IndexingResults,其类型现在 IList<IndexingResult>为 。
示例:
如果代码如下所示:
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)));
}
可以将其更改为这样以修复任何构建错误:
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)));
}
操作方法更改
Azure 搜索 .NET SDK 中的每个操作都公开为一组同步和异步调用方法重载。 这些方法重载的签名和因子分解在版本 1.1 中已更改。
例如,旧版 SDK 中的“获取索引统计信息”作公开了这些签名:
在 IIndexOperations中:
// Asynchronous operation with all parameters
Task<IndexGetStatisticsResponse> GetStatisticsAsync(
string indexName,
CancellationToken cancellationToken);
在 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 中,相同操作的方法签名如下所示:
在 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中:
// 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 以不同的方式组织作方法:
- 可选参数现在建模为默认参数,而不是其他方法重载。 这可以减少方法重载的数量,有时会显著减少。
- 扩展方法现在从调用方隐藏 HTTP 的许多多余的详细信息。 例如,较早版本的 SDK 返回了带有 HTTP 状态码的响应对象,而你通常不需要检查这些对象,因为一旦状态码指示错误,操作方法会抛出
CloudException。 新的扩展方法只返回模型对象,从而节省在代码中解包它们的麻烦。 - 相反,核心接口现在公开了方法,如果需要,可在 HTTP 级别获得更多控制。 现在可以在请求中传入自定义 HTTP 标头,新的
AzureOperationResponse<T>返回类型为操作提供对HttpRequestMessage和HttpResponseMessage的直接访问权限。AzureOperationResponse在Microsoft.Rest.Azure命名空间中定义,并替换Hyak.Common.OperationResponse。
评分参数更改
最新的 SDK 中添加了一个名为ScoringParameter的新类,旨在便于为搜索查询中的评分配置文件提供参数。 以前ScoringProfiles属性的SearchParameters类被类型为IList<string>;现在,它被类型为IList<ScoringParameter>。
示例:
如果代码如下所示:
var sp = new SearchParameters();
sp.ScoringProfile = "jobsScoringFeatured"; // Use a scoring profile
sp.ScoringParameters = new[] { "featuredParam-featured", "mapCenterParam-" + lon + "," + lat };
可以将其更改为这样以修复任何构建错误:
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))
};
模型类更改
由于 Operation 方法更改中所述的签名更改,命名空间中的 Microsoft.Azure.Search.Models 许多类已重命名或删除。 例如:
-
IndexDefinitionResponse已替换为AzureOperationResponse<Index> -
DocumentSearchResponse已重名为DocumentSearchResult -
IndexResult已重名为IndexingResult -
Documents.Count()现在返回一个包含文档计数的long,而不是DocumentCountResponse -
IndexGetStatisticsResponse已重名为IndexGetStatisticsResult -
IndexListResponse已重名为IndexListResult
总之, OperationResponse仅用于包装模型对象的派生类已被删除。 其余类的后缀已从ResponseResult改为 。
示例:
如果代码如下所示:
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;
可以将其更改为这样以修复任何构建错误:
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;
响应类和“IEnumerable”
可能影响代码的其他更改是保存集合的响应类不再实现 IEnumerable<T>。 相反,可以直接访问集合属性。 例如,如果代码如下所示:
DocumentSearchResponse<Hotel> response = indexClient.Documents.Search<Hotel>(searchText, sp);
foreach (SearchResult<Hotel> result in response)
{
Console.WriteLine(result.Document);
}
可以将其更改为这样以修复任何构建错误:
DocumentSearchResult<Hotel> response = indexClient.Documents.Search<Hotel>(searchText, sp);
foreach (SearchResult<Hotel> result in response.Results)
{
Console.WriteLine(result.Document);
}
Web 应用程序的特殊情况
如果 Web 应用程序直接序列化 DocumentSearchResponse 以将搜索结果发送到浏览器,则需要更改代码,否则结果将无法正确序列化。 例如,如果代码如下所示:
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属性来更改它,以修复搜索结果的呈现问题。
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类型object而发出警告。
CloudException 发生更改
该 CloudException 类已从 Hyak.Common 命名空间移动到 Microsoft.Rest.Azure 命名空间。 此外,其 Error 属性已重命名为 Body。
SearchServiceClient 和 SearchIndexClient 的更改
属性 Credentials 的类型已从 SearchCredentials 更改为其基类 ServiceClientCredentials。 如果需要访问SearchIndexClient或SearchServiceClient的SearchCredentials,请使用新SearchCredentials属性。
在旧版 SDK 中,SearchServiceClient 和 SearchIndexClient 都有一个构造函数,该构造函数接受一个 HttpClient 参数。 这些已被替换为采用 HttpClientHandler 和 DelegatingHandler 对象数组的构造函数。 这样,可以更轻松地根据需要安装自定义处理程序来预处理 HTTP 请求。
最后,接收 Uri 和 SearchCredentials 的构造函数已更改。 例如,如果你有如下所示的代码:
var client =
new SearchServiceClient(
new SearchCredentials("abc123"),
new Uri("http://myservice.search.windows.net"));
可以将其更改为这样以修复任何构建错误:
var client =
new SearchServiceClient(
new Uri("http://myservice.search.windows.net"),
new SearchCredentials("abc123"));
另请注意,凭据参数的类型已更改为 ServiceClientCredentials。 这不太可能影响代码,因为 SearchCredentials 派生自 ServiceClientCredentials。
传递请求 ID
在旧版 SDK 中,可以在 SearchServiceClient 或 SearchIndexClient 上设置请求 ID,它会包含在对 REST API 的每个请求中。 如果需要联系支持人员,这对于排查搜索服务问题非常有用。 但是,为每个作设置唯一请求 ID 而不是对所有作使用相同的 ID 更为有用。 因此,已删除SearchServiceClient和SearchIndexClient的方法SetClientRequestId。 相反,可以通过可选 SearchRequestOptions 参数将请求 ID 传递给每个作方法。
注释
在 SDK 的未来版本中,我们将添加一个新机制,用于在客户端对象上全局设置请求 ID,该对象与其他 Azure SDK 使用的方法一致。
示例:
如果您有如下所示的代码:
client.SetClientRequestId(Guid.NewGuid());
...
long count = client.Documents.Count();
可以将其更改为这样以修复任何构建错误:
long count = client.Documents.Count(new SearchRequestOptions(requestId: Guid.NewGuid()));
接口名称更改
操作组接口名称已全部更改,以便与其相应的属性名称保持一致。
-
ISearchServiceClient.Indexes类型已从IIndexOperations中重命名为IIndexesOperations。 -
ISearchServiceClient.Indexers类型已从IIndexerOperations中重命名为IIndexersOperations。 -
ISearchServiceClient.DataSources类型已从IDataSourceOperations中重命名为IDataSourcesOperations。 -
ISearchIndexClient.Documents类型已从IDocumentOperations中重命名为IDocumentsOperations。
除非出于测试目的创建了这些接口的模拟,否则此更改不太可能影响代码。
版本 1.1 中的 Bug 修复
旧版 Azure 搜索 .NET SDK 中存在与自定义模型类序列化相关的 bug。 如果创建了具有不可为 null 值类型的属性的自定义模型类,则可能会出现该 bug。
以下是重现步骤
使用不可为 null 的值类型的属性创建自定义模型类。 例如,添加类型int而不是int?类型的公共UnitCount属性。
如果为该类型的默认值(例如 0 for int)为文档编制索引,则该字段将在 Azure 搜索中为 null。 如果您随后搜索该文档,调用 Search 将抛出 JsonSerializationException,报错它不能将 null 转换为 int。
此外,筛选器可能无法按预期工作,因为 null 写入索引而不是预期值。
更正细节
我们修复了 SDK 版本 1.1 中的此问题。 现在,如果你有如下所示的模型类:
public class Model
{
public string Key { get; set; }
public int IntValue { get; set; }
}
并且将 IntValue 设置为 0,该值现在在传输中正确序列化为 0,并在索引中存储为 0。 往返过程也按预期运作。
此方法存在一个潜在问题:如果使用具有不可为 null 属性的模型类型,则必须 保证 索引中没有文档包含相应字段的 null 值。 SDK 和 Azure 搜索 REST API 都不会帮助你强制实施此 API。
这不仅仅是一个假设的问题:想象一下,向 Edm.Int32类型的现有索引添加新字段的情况。 更新索引定义后,所有文档都将具有该新字段的 null 值(因为所有类型在 Azure 搜索中可为 null)。 如果随后对该字段使用具有不可为 null 的 int 属性的模型类,则在尝试检索文档时会收到如下所示的 JsonSerializationException:
Error converting value {null} to type 'System.Int32'. Path 'IntValue'.
出于此原因,我们仍建议在模型类中使用可为 null 的类型作为最佳做法。
有关此 bug 和修补程序的更多详细信息,请参阅 GitHub 上的此问题。