🔄

Microsoft Bot Framework v4 を Microsoft 365 Agents SDK に移行してみた

2024/11/22に公開

はじめに

Microsoft Ignite 2024 で公開された Microsoft 365 Agents SDK を試すため Microsoft Bot Framework で構築したボットを移行してみました。実際に移行してみての気づきをまとめてみます。

ポイント

コントローラーの変更

リクエストを受け付ける BotController クラスのパラメーターが変更になりました。

  public class BotController : ControllerBase
  {

-     private readonly IBotFrameworkHttpAdapter _adapter;
+     private readonly IBotHttpAdapter _adapter;

      private readonly IBot _bot;

-     public BotController(IBotFrameworkHttpAdapter adapter, IBot bot)
+     public BotController(IBotHttpAdapter adapter, IBot bot)
      {
        _adapter = adapter;
        _bot = bot;
      }

  }

エラー ハンドラーの変更

これまではエラー ハンドラーとして AdapterWithErrorHandler クラスを登録していたのですが、これが変更になりました。

builder.Services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();

新しい書き方では、基本的に AdapterWithErrorHandler が不要になりました。既定の CloudAdapter クラスが予期しない例外が発生したときのハンドリングをしてくれます。

builder.Services.AddCloudAdapter();

これまで通り、自前の AdapterWithErrorHandler クラスを使いたい場合は以下のようにします。

builder.Services.AddCloudAdapter<AdapterWithErrorHandler>();

依存関係の追加

いくつかの依存関係が追加で必要です。

builder.Services.AddSingleton<IConnections, ConfigurationConnections>();
builder.Services.AddSingleton<IChannelServiceClientFactory, RestChannelServiceClientFactory>();

認証方法の変更

ConfigurationBotFrameworkAuthentication クラスを使った認証は廃止されました。代わりに MSAL を使用します。以下は README.md からの転記です。

https://github.com/microsoft/Agents-for-net/tree/25f6a4c48d3b11df36ec95ba8ced174d4fd859f3/src/libraries/Authentication/Authentication.Msal/

public static void AddBotAspNetAuthentication(this IServiceCollection services, IConfiguration configuration, string botConnectionConfig = "Connections:BotServiceConnection:Settings")
{
    var tokenValidationSection = configuration.GetSection("TokenValidation");

    var validTokenIssuers = tokenValidationSection.GetSection("ValidIssuers").Get<List<string>>();

    // If ValidIssuers is empty, default for ABS Public Cloud
    if (validTokenIssuers == null || validTokenIssuers.Count == 0)
    {
        validTokenIssuers =
        [
            "https://api.botframework.com",
            "https://sts.windows.net/d6d49420-f39b-4df7-a1dc-d59a935871db/",
            "https://login.microsoftonline.com/d6d49420-f39b-4df7-a1dc-d59a935871db/v2.0",
            "https://sts.windows.net/f8cdef31-a31e-4b4a-93e4-5f571e91255a/",
            "https://login.microsoftonline.com/f8cdef31-a31e-4b4a-93e4-5f571e91255a/v2.0",
        ];

        var tenantId = configuration[$"{botConnectionConfig}:TenantId"];
        if (!string.IsNullOrEmpty(tenantId))
        {
            validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidTokenIssuerUrlTemplateV1, tenantId));
            validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidTokenIssuerUrlTemplateV2, tenantId));
        }
    }

    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(options =>
    {
        options.SaveToken = true;
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ClockSkew = TimeSpan.FromMinutes(5),
            ValidIssuers = validTokenIssuers,
            ValidAudience = configuration[$"{botConnectionConfig}:ClientId"],
            RequireSignedTokens = true,
            SignatureValidator = (token, parameters) => new JwtSecurityToken(token),
        };
    });
}

d6d49420-f39b-4df7-a1dc-d59a935871dbbotframework.com のテナント ID、f8cdef31-a31e-4b4a-93e4-5f571e91255amicrosoftonline.com のテナント ID です。それ以外に自分の組織のテナント ID を登録する感じですね。

あと AddDefaultMsalAuth メソッドも呼ぶ必要があります。

builder.Services.AddDefaultMsalAuth(configuration);

アダプティブ カードの変更

アダプティブ カードの作成は AdaptiveCards.Templating を使います。AdaptiveCardsNewtonsoft.Json に依存しているので、依存していない AdaptiveCards.Templating を使うということのようです。AdaptiveCard クラスのインスタンスを渡してもアダプティブ カードは表示されないので、代わりに JSON 文字列を設定します。

- var card = new AdaptiveCard("1.3");
+ var json = await File.ReadAllTextAsync("card.json");
+ var card = new AdaptiveCardTemplate(json).Expand();
  await stepContext.Context.SendActivityAsync(MessageFactory.Attachment(
      new Attachment()
      {
-         ContentType = AdaptiveCard.ContentType,
+         ContentType = "application/vnd.microsoft.card.adaptive",
          Content = card,
      }
  ));

辞書型データの変更

WaterfallStepContext.Values プロパティや PromptOptions.Validations プロパティのような辞書型のデータの中身に JsonElement が入るようになりました。Newtonsoft.Json から System.Text.Json に変更したことで、動作が怪しい気がするので、注意が必要です。

おわりに

ほかにも、DialogTestClient クラスが提供されていないので、テストができないといった問題があります。まだこれからという感じがあるので不具合を見つけたらどんどん Issue を投げましょう。

Discussion