Azure Search .NET SDK バージョン 1.1 へのアップグレード

バージョン 1.0.2-preview 以前の Azure Search .NET SDK を使用している場合、この記事はバージョン 1.1 を使用するようにアプリケーションをアップグレードするのに役立ちます。

例を含む SDK のより一般的なチュートリアルについては、「 .NET アプリケーションから Azure Search を使用する方法」を参照してください。

バージョン 1.1 にアップグレードした後、または既に 1.1 から 2.0 プレビューまでのバージョンを使用している場合は、バージョン 3 にアップグレードする必要があります。 手順については、 Azure Search .NET SDK バージョン 3 へのアップグレード を参照してください。

まず、NuGet パッケージ マネージャー コンソールを使用するか、プロジェクト参照を右クリックして [NuGet パッケージの管理...] を選択して、Microsoft.Azure.Search の NuGet 参照を更新します。Visual Studio で〘

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

次の手順では、ビルド エラーを 1 つずつ修正します。 ほとんどの場合、SDK で名前が変更されたクラス名とメソッド名を変更する必要があります。 バージョン 1.1 の破壊的変更の一覧 には、これらの名前の変更の一覧が含まれています。

カスタム クラスを使用してドキュメントをモデル化し、それらのクラスに null 非許容プリミティブ型のプロパティ (C# の intbool など) がある場合は、1.1 バージョンの SDK でバグ修正が行われ、その点に注意する必要があります。 詳細については、 バージョン 1.1 のバグ修正 を参照してください。

最後に、ビルド エラーを修正したら、必要に応じて新しい機能を利用するようにアプリケーションに変更を加えることができます。

バージョン 1.1 での破壊的変更の一覧

次の一覧は、変更がアプリケーション コードに影響を与える可能性によって並べ替わります。

IndexBatch と IndexAction の変更

IndexBatch.Create の名前が IndexBatch.New に変更され、params 引数がなくなりました。 IndexBatch.New は、さまざまな種類のアクション (マージ、削除など) を混在するバッチに使用できます。 さらに、すべてのアクションが同じバッチを作成するための新しい静的メソッドがあります。DeleteMergeMergeOrUploadUpload

IndexAction はパブリック コンストラクターを持たなくなり、そのプロパティは変更できなくなりました。 DeleteMergeMergeOrUploadUploadなど、さまざまな目的でアクションを作成するには、新しい静的メソッドを使用する必要があります。 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 Search .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 Search .NET SDK では、操作方法が異なる方法で整理されています。

  • 省略可能なパラメーターは、追加のメソッド オーバーロードではなく、既定のパラメーターとしてモデル化されるようになりました。 これにより、メソッドのオーバーロードの数が大幅に減少することがあります。
  • 拡張メソッドは、HTTP の余分な詳細の多くを呼び出し元から隠すようになりました。 たとえば、古いバージョンの SDK では HTTP 状態コードを含む応答オブジェクトが返されました。これは、多くの場合、操作メソッドがエラーを示す状態コードに対して CloudException をスローするため、確認する必要はありませんでした。 新しい拡張メソッドはモデルオブジェクトを返すだけで、コード内でラップを解除する手間が省けます。
  • 逆に、コア インターフェイスでは、必要に応じて HTTP レベルでより細かく制御できるメソッドが公開されるようになりました。 要求に含めるカスタム HTTP ヘッダーを渡すようになり、新しい AzureOperationResponse<T> 戻り値の型を使用すると、操作の HttpRequestMessageHttpResponseMessage に直接アクセスできます。 AzureOperationResponseMicrosoft.Rest.Azure 名前空間で定義され、Hyak.Common.OperationResponseに置き換えられます。

ScoringParameters の変更

ScoringParameter という名前の新しいクラスが最新の SDK に追加され、検索クエリのスコアリング プロファイルにパラメーターを簡単に指定できるようになりました。 以前は、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名前空間の多くのクラスの名前が変更または削除されました。 次に例を示します。

  • IndexDefinitionResponseAzureOperationResponse<Index> に置き換えられました
  • DocumentSearchResponse の名前が DocumentSearchResult に変更されました
  • IndexResult の名前が IndexingResult に変更されました
  • Documents.Count() は、long の代わりにドキュメント数を含む DocumentCountResponse を返すようになりました
  • IndexGetStatisticsResponse の名前が IndexGetStatisticsResult に変更されました
  • IndexListResponse の名前が IndexListResult に変更されました

要約すると、モデル オブジェクトをラップするためにのみ存在していた -derived クラス OperationResponseが削除されました。 残りのクラスでは、サフィックスが Response から Resultに変更されています。

コードがこんな感じになっていたら。

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 アプリケーションの特殊なケース

検索結果をブラウザーに送信するために DocumentSearchResponse を直接シリアル化する Web アプリケーションがある場合は、コードを変更する必要があります。そうしないと、結果が正しくシリアル化されません。 たとえば、コードが次のようになります。

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.Dataobject型であるため、コンパイラは警告を表示しません。

CloudException の変更

CloudException クラスは、Hyak.Common 名前空間から Microsoft.Rest.Azure 名前空間に移動しました。 また、その Error プロパティの名前が Bodyに変更されました。

SearchServiceClient と SearchIndexClient の変更

Credentials プロパティの型が、SearchCredentials から基底クラス (ServiceClientCredentials) に変更されました。 SearchCredentials または SearchIndexClientSearchServiceClient にアクセスする必要がある場合は、新しい SearchCredentials プロパティを使用してください。

以前のバージョンの SDK では、SearchServiceClientSearchIndexClient には、HttpClient パラメーターを受け取るコンストラクターがありました。 これらは、HttpClientHandlerDelegatingHandler オブジェクトの配列を受け取るコンストラクターに置き換えられました。 これにより、カスタム ハンドラーをインストールして、必要に応じて HTTP 要求を前処理しやすくなります。

最後に、UriSearchCredentials を受け取ったコンストラクターが変更されました。 たとえば、次のようなコードがある場合は、次のようになります。

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に変更されていることにも注意してください。 SearchCredentialsServiceClientCredentialsから派生しているため、これはコードに影響を与える可能性はほとんどありません。

要求 ID を渡す

古いバージョンの SDK では、SearchServiceClient または SearchIndexClient に要求 ID を設定することができ、REST API へのすべての要求に含まれます。 これは、サポートに問い合わせる必要がある場合に、検索サービスに関する問題のトラブルシューティングに役立ちます。 ただし、すべての操作に同じ ID を使用するのではなく、すべての操作に一意の要求 ID を設定する方が便利です。 このため、SetClientRequestIdSearchServiceClientSearchIndexClient メソッドは削除されています。 代わりに、省略可能な SearchRequestOptions パラメーターを使用して、各操作メソッドに要求 ID を渡すことができます。

SDK の今後のリリースでは、他の Azure SDK で使用されるアプローチと一致するクライアント オブジェクトに要求 ID をグローバルに設定するための新しいメカニズムを追加します。

次のようなコードがある場合:

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 のバグ修正

以前のバージョンの Azure Search .NET SDK には、カスタム モデル クラスのシリアル化に関連するバグがあります。 このバグは、null 非許容値型のプロパティを持つカスタム モデル クラスを作成した場合に発生する可能性があります。

再現手順

null 非許容値型のプロパティを持つカスタム モデル クラスを作成します。 たとえば、UnitCountではなく、int 型のパブリック int? プロパティを追加します。

その種類の既定値 (たとえば、intの場合は 0) でドキュメントのインデックスを作成すると、Azure Search のフィールドは null になります。 その後、そのドキュメントを検索すると、Search の呼び出しで JsonSerializationException が発生し、nullintに変換できないというエラーが報告されます。

また、意図した値の代わりに null がインデックスに書き込まれたため、フィルターが期待どおりに機能しない可能性があります。

詳細を修正する

SDK のバージョン 1.1 でこの問題を修正しました。 ここで、次のようなモデル クラスがある場合:

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

    public int IntValue { get; set; }
}

IntValue を 0 に設定すると、その値がネットワーク上で 0 として正しくシリアル化され、インデックスに 0 として格納されるようになりました。 ラウンドトリップも期待通りに動作します。

この方法には注意すべき潜在的な問題が1つあります。非ヌル制約のあるプロパティを持つモデル型を使用する場合は、インデックス内のドキュメントに対応するフィールドの null 値が含まれないことを 保証 する必要があります。 SDK と Azure Search REST API のどちらも、これを適用するのに役立ちません。

これは単なる仮定上の問題ではありません。Edm.Int32型の既存のインデックスに新しいフィールドを追加するシナリオを想像してください。 インデックス定義を更新すると、すべてのドキュメントにその新しいフィールドの null 値が設定されます (Azure Search ではすべての型が null 許容であるため)。 その後、そのフィールドに null 非許容の int プロパティを持つモデル クラスを使用すると、ドキュメントを取得しようとしたときに次のような JsonSerializationException が表示されます。

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

このため、モデル クラスでは、ベスト プラクティスとして null 許容型を使用することをお勧めします。

このバグと修正プログラムの詳細については、 GitHub でこの問題を参照してください。