2016-08-07 30 views
8

Ich habe versucht, einen Dienst zu einem LuisDialog vom MessagesController wie so passieren:Injizieren externe Abhängigkeiten in Microsoft Bot Framework-Dialog mit Autofac

public async Task<HttpResponseMessage> Post([FromBody]Activity activity) 
... 
await Conversation.SendAsync(activity,() => new ActionDialog(botService)); 

Die botService injiziert wird, in die MessageController Dependency Injection verwenden.

Wenn ich einen Bot Gespräch zu starten bekomme ich einen Fehler:

Typ 'ThetaBot.Services.BotService' in Versammlung ThetaBot.Services, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null "ist nicht als serialisierbar gekennzeichnet

Umsah für eine Lösung, die ich finden kann: https://github.com/Microsoft/BotBuilder/issues/106

I understand your question better now. We have a similar issue with service objects that we want to instantiate from the container rather than from the serialized blob. Here is how we register those objects in the container - we apply special handling during deserialiation for all objects with the key Key_DoNotSerialize:

builder 
     .RegisterType<BotToUserQueue>() 
     .Keyed<IBotToUser>(FiberModule.Key_DoNotSerialize) 
     .AsSelf() 
     .As<IBotToUser>() 
     .SingleInstance(); 

Allerdings kann ich kein Beispiel oder Dokumentation, die beschreibt, wie Sie Ihre eigenen Abhängigkeiten in die bestehenden Bot Rahmenmodule registrieren.

Ich fand auch https://github.com/Microsoft/BotBuilder/issues/252, die angibt, dass es möglich sein sollte, die Dialoge aus dem Container zu instanziieren.

Ich habe diesen Vorschlag versucht:

Func<IDialog<object>> makeRoot =() => actionDialog; 
await Conversation.SendAsync(activity, makeRoot); 

Zusammen mit:

builder 
      .RegisterType<ActionDialog>() 
      .Keyed<ActionDialog>(FiberModule.Key_DoNotSerialize) 
      .AsSelf() 
      .As<ActionDialog>() 
      .SingleInstance(); 

Das funktioniert nicht.

habe ich auch versucht:

var builder = new ContainerBuilder(); 
builder.RegisterModule(new DialogModule_MakeRoot()); 

// My application module 
builder.RegisterModule(new ApplicationModule()); 

using (var container = builder.Build()) 
using (var scope = DialogModule.BeginLifetimeScope(container, activity)) 
{ 
    await Conversation.SendAsync(activity,() => scope.Resolve<ActionDialog>()); 
} 

zusammen mit den folgenden in der ApplicationModule:

  builder 
      .RegisterType<ActionDialog>() 
      .Keyed<ActionDialog>(FiberModule.Key_DoNotSerialize) 
      .AsSelf() 
      .As<ActionDialog>() 
      .SingleInstance(); 

Dies funktioniert nicht und ich begegne das gleiche Problem.

Wenn ich einfach alle Dienste und ihre Abhängigkeiten als serialisierbar markieren, kann ich dies ohne die Notwendigkeit, FiberModule.Key_DoNotSerialize verwenden zu können.

Die Frage ist - was ist die richtige/bevorzugte/empfohlene Möglichkeit zum Registrieren und injizieren Abhängigkeiten in Bot Framework Dialoge?

+0

Ich glaube, Sie haben diese Ausnahme nicht wegen falscher Injektion, sondern weil Sie ein nicht-statisches Feld 'ThetaBot.Services.BotService' Typ in Ihrem Dialog haben. Während dieser Typ nicht als serialisierbar gekennzeichnet ist, kann er nicht unabhängig davon verwendet werden, ob er injiziert wird oder nicht. Wenn Sie alle Services mit ihren Abhängigkeiten serialisieren und mit dem Status Dialog speichern möchten, müssen Sie 'FiberModule.Key_DoNotSerialize' nicht verwenden. In einem anderen Fall können Sie Ihre Dienste an einem anderen Ort einfügen und sie aus dem Dialog verwenden, ohne dort zu speichern. –

+0

Hi @ jim.taylor, Haben Sie die Lösung für dieses Problem bekommen? Ich versuche auch, den Dienst zum Formularflussdialog zu übergeben. –

+1

@MurtazaTahirAli - Ich habe einen Workaround für jetzt verwendet. Ich habe den injizierten Dienst statisch gemacht. [Serializable] öffentliche Klasse ActionDialog: LuisDialog { private statische IBotService _botService; öffentlicher ActionDialog (IBotService botService) { _botService = botService; } –

Antwort

7

In den Global.asax.cs können Sie Ihre Dienste/Dialoge tun tun registrieren Folgendes:

ContainerBuilder builder = new ContainerBuilder(); 

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

builder.RegisterType<JobsMapper>() 
    .Keyed<IMapper<DocumentSearchResult, GenericSearchResult>>(FiberModule.Key_DoNotSerialize) 
    .AsImplementedInterfaces() 
    .SingleInstance(); 

builder.RegisterType<AzureSearchClient>() 
    .Keyed<ISearchClient>(FiberModule.Key_DoNotSerialize) 
    .AsImplementedInterfaces() 
    .SingleInstance(); 

builder.Update(Conversation.Container); 

In Ihrem Controller können Sie dann lösen Ihre Hauptdialog als:

using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity)) 
{ 
    await Conversation.SendAsync(activity,() => scope.Resolve<IDialog<object>>()); 
} 
+0

-Update ist __Obselete__ diesen Tagen (Container werden unveränderlich angesehen, lardidadi), Ersatz hoffentlich im Gange ist: https://github.com/Microsoft/BotBuilder/issues/1966 – flq

+2

Der Ersatz ist Conversation.UpdateContainer –

+0

Für diejenigen zu verwenden, die Informationen zum Verwenden von UpdateContainer finden Sie im Beispiel zu [ContosoFlower] (https://github.com/Microsoft/BotBuilder-Samples/commit/09b58274fe9935de3c13660f4adf30d4ea3b2d77). –