2016-11-08 8 views
3

私はBOTの外部ログインを実装しました。外部サイトからBotコールバックメソッドを呼び出す場合、トークンとユーザー名をPrivateConversationDataに設定してから、"Welcome back [username]!"のようなメッセージでチャットを再開する必要があります。LUIS BotのフレームワークはIntentを外部呼び出しから呼び出さない

このメッセージを表示するには、私はMessageActivityを送信しますが、このアクティビティはチャットに接続することはなく、適切な[LuisIntent("UserIsAuthenticated")]を送信しません。

他のインテントは、ログインフローから期待どおりに動作します。

これは、コールバックメソッドである:

public class OAuthCallbackController : ApiController 
{ 
    [HttpGet] 
    [Route("api/OAuthCallback")] 
    public async Task OAuthCallback([FromUri] string userId, [FromUri] string botId, [FromUri] string conversationId, 
     [FromUri] string channelId, [FromUri] string serviceUrl, [FromUri] string locale, 
     [FromUri] CancellationToken cancellationToken, [FromUri] string accessToken, [FromUri] string username) 
    { 
     var resumptionCookie = new ResumptionCookie(TokenDecoder(userId), TokenDecoder(botId), 
      TokenDecoder(conversationId), channelId, TokenDecoder(serviceUrl), locale); 

      var container = WebApiApplication.FindContainer(); 

      var message = resumptionCookie.GetMessage(); 
      message.Text = "UserIsAuthenticated"; 

      using (var scope = DialogModule.BeginLifetimeScope(container, message)) 
      { 
       var botData = scope.Resolve<IBotData>(); 
       await botData.LoadAsync(cancellationToken); 

       botData.PrivateConversationData.SetValue("accessToken", accessToken); 
       botData.PrivateConversationData.SetValue("username", username); 

       ResumptionCookie pending; 
       if (botData.PrivateConversationData.TryGetValue("persistedCookie", out pending)) 
       { 
        botData.PrivateConversationData.RemoveValue("persistedCookie"); 
        await botData.FlushAsync(cancellationToken); 
       } 

       var stack = scope.Resolve<IDialogStack>(); 
       var child = scope.Resolve<MainDialog>(TypedParameter.From(message)); 
       var interruption = child.Void<object, IMessageActivity>(); 

       try 
       { 
        stack.Call(interruption, null); 

        await stack.PollAsync(cancellationToken); 
       } 
       finally 
       { 
        await botData.FlushAsync(cancellationToken); 
       } 
      } 
     } 
    } 

    public static string TokenDecoder(string token) 
    { 
     return Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(token)); 
    } 
} 

これはコントローラである:

public class MessagesController : ApiController 
{ 
    private readonly ILifetimeScope scope; 

    public MessagesController(ILifetimeScope scope) 
    { 
     SetField.NotNull(out this.scope, nameof(scope), scope); 
    } 

    public async Task<HttpResponseMessage> Post([FromBody] Activity activity, CancellationToken token) 
    { 
     if (activity != null) 
     { 
      switch (activity.GetActivityType()) 
      { 
       case ActivityTypes.Message: 
        using (var scope = DialogModule.BeginLifetimeScope(this.scope, activity)) 
        { 
         var postToBot = scope.Resolve<IPostToBot>(); 
         await postToBot.PostAsync(activity, token); 
        } 
        break; 
      } 
     } 

     return new HttpResponseMessage(HttpStatusCode.Accepted); 
    } 
} 

これは、Iコンポーネントを登録する方法である:

protected override void Load(ContainerBuilder builder) 
    { 
     base.Load(builder); 

     builder.Register(
      c => new LuisModelAttribute("myId", "SubscriptionKey")) 
      .AsSelf() 
      .AsImplementedInterfaces() 
      .SingleInstance(); 

     builder.RegisterType<MainDialog>().AsSelf().As<IDialog<object>>().InstancePerDependency(); 

     builder.RegisterType<LuisService>() 
      .Keyed<ILuisService>(FiberModule.Key_DoNotSerialize) 
      .AsImplementedInterfaces() 
      .SingleInstance(); 
    } 

これはダイアログである。

[Serializable] 
public sealed class MainDialog : LuisDialog<object> 
{ 
    public static readonly string AuthTokenKey = "TestToken"; 
    public readonly ResumptionCookie ResumptionCookie; 
    public static readonly Uri CloudocOauthCallback = new Uri("http://localhost:3980/api/OAuthCallback"); 

    public MainDialog(IMessageActivity activity, ILuisService luis) 
     : base(luis) 
    { 
     ResumptionCookie = new ResumptionCookie(activity); 
    } 

    [LuisIntent("")] 
    public async Task None(IDialogContext context, LuisResult result) 
    { 
     await context.PostAsync("Sorry cannot understand!"); 
     context.Wait(MessageReceived); 
    } 

    [LuisIntent("UserAuthenticated")] 
    public async Task UserAuthenticated(IDialogContext context, LuisResult result) 
    { 
     string username; 
     context.PrivateConversationData.TryGetValue("username", out username); 

     await context.PostAsync($"Welcome back {username}!"); 
     context.Wait(MessageReceived); 
    } 

    [LuisIntent("Login")] 
    private async Task LogIn(IDialogContext context, LuisResult result) 
    { 
     string token; 
     if (!context.PrivateConversationData.TryGetValue(AuthTokenKey, out token)) 
     { 
      context.PrivateConversationData.SetValue("persistedCookie", ResumptionCookie); 

      var loginUrl = CloudocHelpers.GetLoginURL(ResumptionCookie, OauthCallback.ToString()); 

      var reply = context.MakeMessage(); 

      var cardButtons = new List<CardAction>(); 
      var plButton = new CardAction 
      { 
       Value = loginUrl, 
       Type = ActionTypes.Signin, 
       Title = "Connetti a Cloudoc" 
      }; 
      cardButtons.Add(plButton); 
      var plCard = new SigninCard("Connect", cardButtons); 

      reply.Attachments = new List<Attachment> 
      { 
       plCard.ToAttachment() 
      }; 

      await context.PostAsync(reply); 
      context.Wait(MessageReceived); 
     } 
     else 
     { 
      context.Done(token); 
     } 
    } 
} 

私が恋しいのは?

更新もコールバックメソッドにResumeAsyncてみました

var container = WebApiApplication.FindContainer(); 

var message = resumptionCookie.GetMessage(); 
message.Text = "UserIsAuthenticated"; 

using (var scope = DialogModule.BeginLifetimeScope(container, message)) 
{ 
    var botData = scope.Resolve<IBotData>(); 
    await botData.LoadAsync(cancellationToken); 

    botData.PrivateConversationData.SetValue("accessToken", accessToken); 
    botData.PrivateConversationData.SetValue("username", username); 

    ResumptionCookie pending; 
    if (botData.PrivateConversationData.TryGetValue("persistedCookie", out pending)) 
    { 
     botData.PrivateConversationData.RemoveValue("persistedCookie"); 
     await botData.FlushAsync(cancellationToken); 
    } 

    await Conversation.ResumeAsync(resumptionCookie, message, cancellationToken); 
} 

が、それは私にEzequielに続いて、エラーOperation is not valid due to the current state of the object.

アップデート2

を与えますアイデア私はこの方法で私のコードを変更:

[HttpGet] 
    [Route("api/OAuthCallback")] 
    public async Task OAuthCallback(string state, [FromUri] string accessToken, [FromUri] string username) 
    { 
     var resumptionCookie = ResumptionCookie.GZipDeserialize(state); 
     var message = resumptionCookie.GetMessage(); 
     message.Text = "UserIsAuthenticated"; 

     await Conversation.ResumeAsync(resumptionCookie, message); 
    } 

resumptionCookieは大丈夫のようだ:

enter image description here

しかしawait Conversation.ResumeAsync(resumptionCookie, message);あなたはとの会話を再開する必要がエラーに私にOperation is not valid due to the current state of the object.

+0

MainDialogを追加できますか? –

+0

私はそれを追加しました! – danyolgiax

+0

タイプミスはありませんか? 2つの異なる単語を使用する:UserIsAuthenticatedとUserAuthenticated – K48

答えて

0

私はそれを動作させる方法を見つけました。

コントローラー:

public class MessagesController : ApiController 
{ 
    public async Task<HttpResponseMessage> Post([FromBody] Activity activity, CancellationToken token) 
    { 
     if (activity != null) 
     { 
      switch (activity.GetActivityType()) 
      { 
       case ActivityTypes.Message: 

        var container = WebApiApplication.FindContainer(); 

        using (var scope = DialogModule.BeginLifetimeScope(container, activity)) 
        { 
         await Conversation.SendAsync(activity,() => scope.Resolve<IDialog<object>>(), token); 
        } 
        break; 
      } 
     } 
     return new HttpResponseMessage(HttpStatusCode.Accepted); 
    } 
} 

Global.asaxの

public class WebApiApplication : System.Web.HttpApplication 
{ 
    protected void Application_Start() 
    { 
     GlobalConfiguration.Configure(WebApiConfig.Register); 

     var builder = new ContainerBuilder(); 

     builder.RegisterModule(new DialogModule()); 

     builder.RegisterModule(new MyModule()); 

     var config = GlobalConfiguration.Configuration; 

     builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); 

     builder.RegisterWebApiFilterProvider(config); 

     var container = builder.Build(); 
     config.DependencyResolver = new AutofacWebApiDependencyResolver(container); 
    } 

    public static ILifetimeScope FindContainer() 
    { 
     var config = GlobalConfiguration.Configuration; 
     var resolver = (AutofacWebApiDependencyResolver)config.DependencyResolver; 
     return resolver.Container; 
    } 
} 

MyModuleという:

public sealed class MyModule : Module 
{ 
    protected override void Load(ContainerBuilder builder) 
    { 
     base.Load(builder); 

     builder.Register(
      c => new LuisModelAttribute("MyId", "SubId")) 
      .AsSelf() 
      .AsImplementedInterfaces() 
      .SingleInstance(); 

     builder.RegisterType<MainDialog>().AsSelf().As<IDialog<object>>().InstancePerDependency(); 

     builder.RegisterType<LuisService>() 
      .Keyed<ILuisService>(FiberModule.Key_DoNotSerialize) 
      .AsImplementedInterfaces() 
      .SingleInstance(); 
    } 
} 

コールバックメソッド

public class OAuthCallbackController : ApiController 
{ 

    [HttpGet] 
    [Route("api/OAuthCallback")] 
    public async Task OAuthCallback(string state, [FromUri] CancellationToken cancellationToken, [FromUri] string accessToken, [FromUri] string username) 
    { 
     var resumptionCookie = ResumptionCookie.GZipDeserialize(state); 
     var message = resumptionCookie.GetMessage(); 
     message.Text = "UserIsAuthenticated"; 

     using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message)) 
     { 
      var dataBag = scope.Resolve<IBotData>(); 
      await dataBag.LoadAsync(cancellationToken); 

      dataBag.PrivateConversationData.SetValue("accessToken", accessToken); 
      dataBag.PrivateConversationData.SetValue("username", username); 

      ResumptionCookie pending; 
      if (dataBag.PrivateConversationData.TryGetValue("persistedCookie", out pending)) 
      { 
       dataBag.PrivateConversationData.RemoveValue("persistedCookie"); 
       await dataBag.FlushAsync(cancellationToken); 
      } 
     } 

     await Conversation.ResumeAsync(resumptionCookie, message, cancellationToken); 
    } 
0

を与え続けますボットはそのメッセージが到着しない可能性が高い理由です。

代わりにダイアログスタックを使用するのでは、あなたの認証のニーズに応じて

await Conversation.ResumeAsync(resumptionCookie, message); 

を使用してみてください、あなたはAuthBotを検討する必要があります。ライブラリーのOAuthCallbackコントローラーのlogicを見て、認証後にボットと会話を再開する方法を知ることもできます。

ContosoFlowersの例では、resume conversation mechanismも使用しています。認証目的ではなく、hypotethicalクレジットカード決済を処理する方法を示すためです。

+0

ダイアログスタックの代わりに 'ResumeAsync'を試してみると、'操作はオブジェクトの現在の状態のため有効ではありません。 ' – danyolgiax

+0

問題がどこで起こっているのかよく分かりません。それを行う方法は、私が提供した例に示すようにResumeAsyncを使用しています。州の周りのすべてのコードをコメントアウトして、resumptionCookie.GetMessageを終了して何が起こるかを見てみましょう。あなたは、クッキーを再現するために使用している値が期待されている値であると確信していますか?通常、クッキーをシリアル化してデシリアライズしてください(サンプルを参照)。 –

+0

質問が更新されました。 : – danyolgiax

関連する問題