.NET 用Azure Service Bus クライアント ライブラリ - バージョン 7.16.2

Azure Service Busを使用すると、信頼性の高いサービスを使用して非同期メッセージング パターンを利用して、プロデューサーとコンシューマーの間でメッセージを仲介するアプリケーションを構築できます。 Azure Service Busは、クライアントとサーバー間の柔軟な仲介型メッセージングと、複雑なルーティングによる構造化された先入れ先出し (FIFO) メッセージング、およびパブリッシュ/サブスクライブ機能を提供します。 Azure Service Busの詳細については、「Azure Service Busとは」を参照してください。

クライアント ライブラリを使用して、次のAzure Service Busを行います。

  • ビジネス データの転送: メッセージングを利用して、販売や発注書、仕訳帳、在庫移動などの情報を永続的に交換できます。

  • アプリケーションを切り離す: アプリケーションとサービスの信頼性とスケーラビリティが向上し、送信者と受信者が同時にオンラインになる必要が軽減されます。

  • メッセージの処理方法を制御する: キューを使用するメッセージに対して従来の競合コンシューマーをサポートするか、トピックとサブスクリプションを使用して各コンシューマーにメッセージの独自のインスタンスを許可します。

  • 複雑なワークフローを実装する: メッセージ セッションは、メッセージの順序付けまたはメッセージの遅延を必要とするシナリオをサポートします。

ソースコード | パッケージ (NuGet) | API リファレンス ドキュメント | 製品ドキュメント | 移行ガイド (Microsoft.Azure.ServiceBus) | 移行ガイド (WindowsAzure.ServiceBus) | トラブルシューティング ガイド

作業の開始

前提条件

  • Microsoft Azure サブスクリプション:Azure Service Busを含む Azure サービスを使用するには、サブスクリプションが必要です。 既存の Azure アカウントをお持ちでない場合は、無料試用版にサインアップするか、 アカウントの作成時に MSDN サブスクライバー特典を使用できます。

  • Service Bus 名前空間:Azure Service Busと対話するには、名前空間も使用可能である必要があります。 Azure リソースの作成に慣れていない場合は、Azure portalを使用して Service Bus 名前空間を作成するためのステップバイステップ ガイドに従うことをお勧めします。 また、Azure CLI、Azure PowerShell、または Azure Resource Manager (ARM) テンプレートを使用して Service Bus エンティティを作成するための詳細な手順も確認できます。

  • C# 8.0:Azure Service Bus クライアント ライブラリでは、C# 8.0 で導入された新機能が使用されます。 C# 8.0 構文を利用するには、 の言語バージョンlatest.NET Core SDK 3.0 以降を使用してコンパイルすることをお勧めします。

    C# 8.0 構文を最大限に活用したい Visual Studio ユーザーは、Visual Studio 2019 以降を使用する必要があります。 無料の Community エディションを含む Visual Studio 2019 は、[こちら](https://visualstudio.microsoft.com/vs/)からダウンロードできます。 Visual Studio 2017 のユーザーは、 Microsoft.Net.Compilers NuGet パッケージ を使用して言語バージョンを設定することで C# 8 構文を利用できます。ただし、編集エクスペリエンスは理想的ではない場合があります。

    以前の C# 言語バージョンでもライブラリを使用できますが、新しい構文の恩恵を受けるのではなく、非同期列挙可能メンバーと非同期破棄可能メンバーを手動で管理する必要があります。 以前のバージョンの .NET Core や .NET Framework を含め、.NET Core SDK でサポートされているフレームワーク バージョンは引き続き対象にすることができます。 詳細については、「 ターゲット フレームワークを指定する方法」を参照してください。

    重要な注意:サンプルサンプルを変更せずにビルドまたは実行するには、C# 8.0 の使用が必須です。 他の言語バージョン用に調整する場合は、引き続きサンプルを実行できます。

Azure で必要な Service Bus リソースをすばやく作成し、それらの接続文字列を受け取るために、次をクリックしてサンプル テンプレートをデプロイできます。

Azure にデプロイする

パッケージをインストールする

NuGet を使用して .NET 用のAzure Service Bus クライアント ライブラリをインストールします。

dotnet add package Azure.Messaging.ServiceBus

クライアントを認証する

Service Bus クライアント ライブラリがキューまたはトピックと対話するには、接続して承認する方法を理解する必要があります。 これを行う最も簡単な方法は、Service Bus 名前空間の作成時に自動的に作成される接続文字列を使用することです。 Azure の共有アクセス ポリシーに慣れていない場合は、ステップ バイ ステップ ガイドに従って Service Bus 接続文字列を取得できます。

接続文字列を取得したら、それを使用してクライアントを認証できます。

// Create a ServiceBusClient that will authenticate using a connection string
string connectionString = "<connection_string>";
await using var client = new ServiceBusClient(connectionString);

Azure.Identity を使用して認証する方法を確認するには、この を参照してください。

ASP.NET Core アプリケーションの認証方法の例については、このを参照してください。

カスタム エンドポイントを使用して接続を開始する方法を確認するには、この サンプルを参照してください。

主要な概念

を初期化 ServiceBusClientしたら、Service Bus 名前空間内のプライマリ リソースの種類とやり取りできます。その中には、複数のリソースが存在する可能性があり、実際のメッセージ転送が行われる場合、名前空間は多くの場合、アプリケーション コンテナーとして機能します。

  • キュー: メッセージの送受信を許可します。 多くの場合、ポイントツーポイント通信に使用されます。

  • トピック: キューとは対照的に、トピックは発行/サブスクライブのシナリオに適しています。 トピックはに送信できますが、使用するサブスクリプションが必要です。そのサブスクリプションには複数の並列が存在する可能性があります。

  • サブスクリプション: トピックから使用するメカニズム。 各サブスクリプションは独立しており、トピックに送信された各メッセージのコピーを受け取ります。 ルールとフィルターを使用して、特定のサブスクリプションで受信するメッセージを調整できます。

これらのリソースの詳細については、「Azure Service Busとは」を参照してください。

これらのリソースを操作するには、次の SDK の概念をよく理解している必要があります。

  • Service Bus クライアントは、開発者が Service Bus クライアント ライブラリを操作するための主要なインターフェイスです。 これは、ライブラリとのすべての対話が発生するゲートウェイとして機能します。

  • Service Bus 送信者のスコープは特定のキューまたはトピックであり、Service Bus クライアントを使用して作成されます。 送信者は、キューまたはトピックにメッセージを送信できます。 また、指定した日付に配信できるようにメッセージをスケジュールすることもできます。

  • Service Bus レシーバーは、特定のキューまたはサブスクリプションにスコープが設定され、Service Bus クライアントを使用して作成されます。 受信側を使用すると、キューまたはサブスクリプションからメッセージを受信できます。 また、メッセージを受信した後にメッセージを解決することもできます。 メッセージをセトリングするには、次の 4 つの方法があります。

    • 完了 - キューまたはトピックからメッセージが削除されます。
    • 破棄 - メッセージに対する受信者のロックを解除し、他の受信者がメッセージを受信できるようにします。
    • Defer - 通常の方法でメッセージが受信されないようにします。 遅延メッセージを受信するには、メッセージのシーケンス番号を保持する必要があります。
    • DeadLetter - メッセージを配信不能キューに移動します。 これにより、メッセージが再び受信されなくなります。 配信不能キューからメッセージを受信するには、配信不能キューをスコープとする受信者が必要です。
  • Service Bus セッション レシーバーは、特定のセッション対応キューまたはサブスクリプションにスコープが設定され、Service Bus クライアントを使用して作成されます。 セッション レシーバーは標準レシーバーとほぼ同じですが、セッション管理操作はセッションが有効なエンティティにのみ適用されるという違いがあります。 これらの操作には、セッション状態の取得と設定、セッション ロックの更新が含まれます。

  • Service Bus プロセッサは、特定のキューまたはサブスクリプションにスコープが設定され、Service Bus クライアントを使用して作成されます。 は ServiceBusProcessor 、一連のレシーバーに関する抽象化と考えることができます。 コールバック モデルを使用して、メッセージを受信したときと例外が発生したときにコードを指定できるようにします。 処理されたメッセージの自動完了、メッセージ ロックの自動更新、およびユーザー指定のイベント ハンドラーの同時実行が提供されます。 機能セットのため、Service Bus エンティティから受信するアプリケーションを作成するための go to ツールである必要があります。 ServiceBusReceiver は、ServiceBusReceiver を直接使用するときにプロセッサが期待できるきめ細かい制御をプロセッサが提供できない、より複雑なシナリオに推奨されます。

  • Service Bus セッション プロセッサは、特定のセッションが有効なキューまたはサブスクリプションにスコープが設定され、Service Bus クライアントを使用して作成されます。 セッション プロセッサは標準プロセッサとほぼ同じですが、セッションが有効なエンティティにのみ適用されるセッション管理操作が公開される点が異なります。

その他の概念と詳細な説明については、「 Service Bus の高度な機能」を参照してください。

クライアントの有効期間

ServiceBusClient送信側、受信側、およびプロセッサは、アプリケーションの有効期間中にシングルトンとしてキャッシュして使用しても安全です。これは、メッセージが定期的に送受信される場合のベスト プラクティスです。 これらは、ネットワーク、CPU、メモリの使用を効率的に管理し、非アクティブな期間中に使用率を低く保つ役割を担います。

これらの型は破棄可能であり、 または CloseAsyncDisposeAsync呼び出して、ネットワーク リソースやその他のアンマネージド オブジェクトが適切にクリーンアップされるようにする必要があります。 インスタンスが破棄されると ServiceBusClient 、インスタンスを使用して作成された送信者、受信者、プロセッサが自動的に閉じられ、クリーンアップされることに注意してください。

スレッド セーフ

すべてのクライアント インスタンス メソッドがスレッド セーフであり、相互に独立していることを保証します (ガイドライン)。 これにより、クライアント インスタンスの再利用に関する推奨事項は、スレッド間でも常に安全になります。

その他の概念

クライアント オプション | 診断 | あざける

メッセージの送受信

メッセージ送信は、 を使用して実行されます ServiceBusSender。 受信は を使用して実行されます ServiceBusReceiver

string connectionString = "<connection_string>";
string queueName = "<queue_name>";
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
await using var client = new ServiceBusClient(connectionString);

// create the sender
ServiceBusSender sender = client.CreateSender(queueName);

// create a message that we can send. UTF-8 encoding is used when providing a string.
ServiceBusMessage message = new ServiceBusMessage("Hello world!");

// send the message
await sender.SendMessageAsync(message);

// create a receiver that we can use to receive the message
ServiceBusReceiver receiver = client.CreateReceiver(queueName);

// the received message is a different type as it contains some service set properties
ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();

// get the message body as a string
string body = receivedMessage.Body.ToString();
Console.WriteLine(body);

メッセージのバッチの送信

一度に複数のメッセージを送信する方法は 2 つあります。 これを行う最初の方法では、セーフ バッチ処理を使用します。 セーフ バッチ処理では、 オブジェクトを ServiceBusMessageBatch 作成できます。これにより、 メソッドを使用して TryAdd 一度に 1 つずつメッセージをバッチに追加できます。 メッセージがバッチに収まらない場合、 TryAdd は false を返します。

// add the messages that we plan to send to a local queue
Queue<ServiceBusMessage> messages = new Queue<ServiceBusMessage>();
messages.Enqueue(new ServiceBusMessage("First message"));
messages.Enqueue(new ServiceBusMessage("Second message"));
messages.Enqueue(new ServiceBusMessage("Third message"));

// create a message batch that we can send
// total number of messages to be sent to the Service Bus queue
int messageCount = messages.Count;

// while all messages are not sent to the Service Bus queue
while (messages.Count > 0)
{
    // start a new batch
    using ServiceBusMessageBatch messageBatch = await sender.CreateMessageBatchAsync();

    // add the first message to the batch
    if (messageBatch.TryAddMessage(messages.Peek()))
    {
        // dequeue the message from the .NET queue once the message is added to the batch
        messages.Dequeue();
    }
    else
    {
        // if the first message can't fit, then it is too large for the batch
        throw new Exception($"Message {messageCount - messages.Count} is too large and cannot be sent.");
    }

    // add as many messages as possible to the current batch
    while (messages.Count > 0 && messageBatch.TryAddMessage(messages.Peek()))
    {
        // dequeue the message from the .NET queue as it has been added to the batch
        messages.Dequeue();
    }

    // now, send the batch
    await sender.SendMessagesAsync(messageBatch);

    // if there are any remaining messages in the .NET queue, the while loop repeats
}

2 番目の方法では、 の SendMessagesAsync IEnumerable ServiceBusMessageを受け入れるオーバーロードを使用します。 このメソッドを使用すると、指定されたすべてのメッセージを、サービスに送信する 1 つのメッセージ バッチに収まるようにします。 メッセージが大きすぎて 1 つのバッチに収まらない場合、操作は例外をスローします。

IList<ServiceBusMessage> messages = new List<ServiceBusMessage>();
messages.Add(new ServiceBusMessage("First"));
messages.Add(new ServiceBusMessage("Second"));
// send the messages
await sender.SendMessagesAsync(messages);

メッセージのバッチの受信

// create a receiver that we can use to receive the messages
ServiceBusReceiver receiver = client.CreateReceiver(queueName);

// the received message is a different type as it contains some service set properties
// a batch of messages (maximum of 2 in this case) are received
IReadOnlyList<ServiceBusReceivedMessage> receivedMessages = await receiver.ReceiveMessagesAsync(maxMessages: 2);

// go through each of the messages received
foreach (ServiceBusReceivedMessage receivedMessage in receivedMessages)
{
    // get the message body as a string
    string body = receivedMessage.Body.ToString();
}

メッセージを完了する

キューまたはサブスクリプションからメッセージを削除するには、 メソッドを CompleteMessageAsync 呼び出します。

string connectionString = "<connection_string>";
string queueName = "<queue_name>";
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
await using var client = new ServiceBusClient(connectionString);

// create the sender
ServiceBusSender sender = client.CreateSender(queueName);

// create a message that we can send
ServiceBusMessage message = new ServiceBusMessage("Hello world!");

// send the message
await sender.SendMessageAsync(message);

// create a receiver that we can use to receive and settle the message
ServiceBusReceiver receiver = client.CreateReceiver(queueName);

// the received message is a different type as it contains some service set properties
ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();

// complete the message, thereby deleting it from the service
await receiver.CompleteMessageAsync(receivedMessage);

メッセージを破棄する

メッセージを破棄すると、受信者のロックが解除され、この受信者または他の受信者がメッセージを受信できるようになります。

ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();

// abandon the message, thereby releasing the lock and allowing it to be received again by this or other receivers
await receiver.AbandonMessageAsync(receivedMessage);

メッセージを延期する

メッセージを遅延すると、 メソッドまたは ReceiveMessagesAsync メソッドを使用してReceiveMessageAsyncメッセージを再受信できなくなります。 代わりに、個別のメソッドとReceiveDeferredMessagesAsyncReceiveDeferredMessageAsync遅延メッセージを受信するための メソッドがあります。

ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();

// defer the message, thereby preventing the message from being received again without using
// the received deferred message API.
await receiver.DeferMessageAsync(receivedMessage);

// receive the deferred message by specifying the service set sequence number of the original
// received message
ServiceBusReceivedMessage deferredMessage = await receiver.ReceiveDeferredMessageAsync(receivedMessage.SequenceNumber);

メッセージの配信不能

メッセージの配信不能は遅延に似ていますが、1 つのメインの違いは、メッセージが一定の回数受信された後にサービスによって自動的に配信不能になることです。 アプリケーションでは、要件に基づいて手動で配信不能メッセージを選択できます。 メッセージが配信不能になると、実際には元のキューのサブキューに移動されます。 ServiceBusReceiverは、メイン キューがセッション対応かどうかに関係なく、配信不能サブキューからメッセージを受信するために使用されることに注意してください。

ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();

// Dead-letter the message, thereby preventing the message from being received again without receiving from the dead letter queue.
// We can optionally pass a dead letter reason and dead letter description to further describe the reason for dead-lettering the message.
await receiver.DeadLetterMessageAsync(receivedMessage, "sample reason", "sample description");

// receive the dead lettered message with receiver scoped to the dead letter queue.
ServiceBusReceiver dlqReceiver = client.CreateReceiver(queueName, new ServiceBusReceiverOptions
{
    SubQueue = SubQueue.DeadLetter
});
ServiceBusReceivedMessage dlqMessage = await dlqReceiver.ReceiveMessageAsync();

// The reason and the description that we specified when dead-lettering the message will be available in the received dead letter message.
string reason = dlqMessage.DeadLetterReason;
string description = dlqMessage.DeadLetterErrorDescription;

詳細については、 ServiceBus 配信不能キューの概要に関するページを参照してください。

プロセッサの使用

ServiceBusProcessor 、一連のレシーバーに関する抽象化と考えることができます。 コールバック モデルを使用して、メッセージの受信時と例外の発生時にコードを指定できるようにします。 処理されたメッセージの自動完了、メッセージ ロックの自動更新、およびユーザー指定のイベント ハンドラーの同時実行が提供されます。 その機能セットのため、Service Bus エンティティから受信するアプリケーションを作成するための go to ツールである必要があります。 ServiceBusReceiver は、プロセッサが ServiceBusReceiver を直接使用するときに期待できるきめ細かい制御を提供できない、より複雑なシナリオに推奨されます。

string connectionString = "<connection_string>";
string queueName = "<queue_name>";
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
await using var client = new ServiceBusClient(connectionString);

// create the sender
ServiceBusSender sender = client.CreateSender(queueName);

// create a set of messages that we can send
ServiceBusMessage[] messages = new ServiceBusMessage[]
{
    new ServiceBusMessage("First"),
    new ServiceBusMessage("Second")
};

// send the message batch
await sender.SendMessagesAsync(messages);

// create the options to use for configuring the processor
var options = new ServiceBusProcessorOptions
{
    // By default or when AutoCompleteMessages is set to true, the processor will complete the message after executing the message handler
    // Set AutoCompleteMessages to false to [settle messages](/azure/service-bus-messaging/message-transfers-locks-settlement#peeklock) on your own.
    // In both cases, if the message handler throws an exception without settling the message, the processor will abandon the message.
    AutoCompleteMessages = false,

    // I can also allow for multi-threading
    MaxConcurrentCalls = 2
};

// create a processor that we can use to process the messages
await using ServiceBusProcessor processor = client.CreateProcessor(queueName, options);

// configure the message and error handler to use
processor.ProcessMessageAsync += MessageHandler;
processor.ProcessErrorAsync += ErrorHandler;

async Task MessageHandler(ProcessMessageEventArgs args)
{
    string body = args.Message.Body.ToString();
    Console.WriteLine(body);

    // we can evaluate application logic and use that to determine how to settle the message.
    await args.CompleteMessageAsync(args.Message);
}

Task ErrorHandler(ProcessErrorEventArgs args)
{
    // the error source tells me at what point in the processing an error occurred
    Console.WriteLine(args.ErrorSource);
    // the fully qualified namespace is available
    Console.WriteLine(args.FullyQualifiedNamespace);
    // as well as the entity path
    Console.WriteLine(args.EntityPath);
    Console.WriteLine(args.Exception.ToString());
    return Task.CompletedTask;
}

// start processing
await processor.StartProcessingAsync();

// since the processing happens in the background, we add a Console.ReadKey to allow the processing to continue until a key is pressed.
Console.ReadKey();

Azure.Identity を使用した認証

Azure Identity ライブラリでは、認証に対する Azure Active Directory のサポートが簡単に提供されます。

// Create a ServiceBusClient that will authenticate through Active Directory
string fullyQualifiedNamespace = "yournamespace.servicebus.windows.net";
await using var client = new ServiceBusClient(fullyQualifiedNamespace, new DefaultAzureCredential());

セッションの操作

セッション は、関連するメッセージをグループ化するためのメカニズムを提供します。 セッションを使用するには、セッションが有効なエンティティを操作する必要があります。

依存関係の挿入に登録 ASP.NET Core

ASP.NET Core アプリに依存関係として挿入ServiceBusClientするには、ASP.NET Core パッケージ用の Azure クライアント ライブラリ統合をインストールします。

dotnet add package Microsoft.Extensions.Azure

次に、サービスが構成されているクライアントを登録します。 ASP.NET Coreアプリケーションの場合、これは多くの場合、 または メソッドでProgram.csStartupConfigureServices直接行われます。

public void ConfigureServices(IServiceCollection services)
{
    services.AddAzureClients(builder =>
    {
        builder.AddServiceBusClient("<< SERVICE BUS CONNECTION STRING >>");
    });

    // Register other services, controllers, and other infrastructure.
}

クライアントに共有 Azure.Identity 資格情報を使用することを好むアプリケーションの場合、登録は若干異なります。

public void ConfigureServices(IServiceCollection services)
 {
     services.AddAzureClients(builder =>
     {
         // This will register the ServiceBusClient using an Azure Identity credential.
         builder.AddServiceBusClientWithNamespace("<< YOUR NAMESPACE >>.servicebus.windows.net");

         // By default, DefaultAzureCredential is used, which is likely desired for most
         // scenarios. If you need to restrict to a specific credential instance, you could
         // register that instance as the default credential instead.
         builder.UseCredential(new ManagedIdentityCredential());
     });

     // Register other services, controllers, and other infrastructure.
 }

また、登録されたServiceBusClientインスタンスを使用して、 や などのServiceBusSenderServiceBusReceiverサブクライアントを DI に登録することもできます。 たとえば、名前空間に属するキューごとに送信者を登録するには、次のようにします。

public async Task ConfigureServicesAsync(IServiceCollection services)
{
    // Query the available queues for the Service Bus namespace.
    var adminClient = new ServiceBusAdministrationClient("<< SERVICE BUS CONNECTION STRING >>");
    var queueNames = new List<string>();

    // Because the result is async, they need to be captured to a standard list to avoid async
    // calls when registering.  Failure to do so results in an error with the services collection.
    await foreach (var queue in adminClient.GetQueuesAsync())
    {
        queueNames.Add(queue.Name);
    }

    // After registering the ServiceBusClient, register a named factory for each
    // queue.  This allows them to be lazily created and managed as singleton instances.

    services.AddAzureClients(builder =>
    {
        builder.AddServiceBusClient("<< SERVICE BUS CONNECTION STRING >>");

        foreach (var queueName in queueNames)
        {
            builder.AddClient<ServiceBusSender, ServiceBusClientOptions>((_, _, provider) =>
                provider
                    .GetService<ServiceBusClient>()
                    .CreateSender(queueName)
            )
            .WithName(queueName);
        }
    });

    // Register other services, controllers, and other infrastructure.
}

送信者は関連付けられたキューに名前が付けられているため、挿入時に直接バインドすることはありません。 代わりに、名前付き送信者を取得するために使用できるファクトリにバインドします。

public class ServiceBusSendingController : ControllerBase
{
    private readonly ServiceBusSender _sender;

    public ServiceBusSendingController(IAzureClientFactory<ServiceBusSender> serviceBusSenderFactory)
    {
        // Though the method is called "CreateClient", the factory will manage the sender as a
        // singleton, creating a new instance only on the first use.
        _sender = serviceBusSenderFactory.CreateClient("<< QUEUE NAME >>");
    }
}

詳細と例については、「 Azure SDK for .NET を使用した依存関係の挿入」を参照してください。

トラブルシューティング

Service Bus トラブルシューティング ガイドを参照してください。

次のステップ

Azure Service Bus クライアント ライブラリでは、説明した入門シナリオ以外にも、Azure Service Bus サービスの完全な機能セットを活用するのに役立つ追加のシナリオのサポートが提供されています。 これらのシナリオの一部を調べるのに役立つよう、Service Bus クライアント ライブラリには、一般的なシナリオの図として機能するサンプルのプロジェクトが用意されています。 詳細については、 README のサンプル を参照してください。

共同作成

このプロジェクトでは、共同作成と提案を歓迎しています。 ほとんどの共同作成では、共同作成者使用許諾契約書 (CLA) にご同意いただき、ご自身の共同作成内容を使用する権利を Microsoft に供与する権利をお持ちであり、かつ実際に供与することを宣言していただく必要があります。 詳細については、 https://cla.microsoft.com を参照してください。

pull request を送信すると、CLA を提供して PR (ラベル、コメントなど) を適宜装飾する必要があるかどうかを CLA ボットが自動的に決定します。 ボットによって提供される手順にそのまま従ってください。 この操作は、Microsoft の CLA を使用するすべてのリポジトリについて、1 回だけ行う必要があります。

このプロジェクトでは、Microsoft オープン ソースの倫理規定を採用しています。 詳しくは、「Code of Conduct FAQ (倫理規定についてよくある質問)」を参照するか、opencode@microsoft.com 宛てに質問またはコメントをお送りください。

詳細については、 投稿ガイド を参照してください。

インプレッション数