Azure / botbuilder-instrumentation-cs

BotBuilder Instrumentation (C#)
MIT License
5 stars 9 forks source link

Problem 'BotBuilder.Instrumentation.Interfaces.IBotFrameworkInstrumentation' Autofac #11

Open eflorespalma opened 6 years ago

eflorespalma commented 6 years ago

I have my bot published in facebook and web and everything work fine. But the problem is when i stop to talk to the bot after 5 hours more or less and i return to talk to the bot again i have this exception The requested service 'BotBuilder.Instrumentation.Interfaces.IBotFrameworkInstrumentation' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency. and to fix this i have to delete the conversation on facebook and talk it again and it works, another thing is that problem is just in facebook in the web chat i dont have problem maybe because i m using directline. I have this code in my IoC

This my autofac class to inject things i need

public static void Configure()
        {
            var builder = new ContainerBuilder();

            #region Modules
            builder.RegisterModule(new DialogModule());
            #endregion

            #region Dialogs
            builder.RegisterType<RootDialog>().As<LuisRootDialog<object>>().InstancePerDependency();
            #endregion

            #region Factory
            builder.RegisterType<DialogFactory>().Keyed<IDialogFactory>(FiberModule.Key_DoNotSerialize).AsImplementedInterfaces().SingleInstance();
            builder.RegisterType<TicketFactory>().Keyed<ITicketFactory>(FiberModule.Key_DoNotSerialize).AsImplementedInterfaces().SingleInstance();
            #endregion

            #region Database
            builder.RegisterGeneric(typeof(DocumentService<>)).As(typeof(IDocumentDbService<>)).SingleInstance();
            #endregion

            #region Web Api Registration
            var config = GlobalConfiguration.Configuration;
            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
            builder.RegisterWebApiFilterProvider(config);
            #endregion

            #region Autofac Container
            builder.Update(container: Conversation.Container);
            config.DependencyResolver = new AutofacWebApiDependencyResolver(Conversation.Container);
            #endregion
        }

And this is my message controller where i resolve my root controller

public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
        {
            if (activity.Type == ActivityTypes.Message)
            {
                            try
                            {
                                LogMessage("Before Open Dialogs");
                                using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity))
                                {
                                    await Conversation.SendAsync(activity, () => scope.Resolve<LuisRootDialog<object>>());
                                }
                            }
                            catch (Exception ex)
                            {
                                LogMessage("Error a Nivel de Abrir el Dialog");
                                LogMessage(ex.Message);
                            }
            }
            else
            {
                await HandleSystemMessage(activity);
            }
            var response = Request.CreateResponse(HttpStatusCode.OK);
            return response;
        }

This is part of my RootDialog

[Serializable]
    public class RootDialog : LuisRootDialog<object>
    {
        #region Properties
        public string Text { get; set; }
        #endregion

        #region Declarations
        readonly IDialogFactory _dialogFactory;
        #endregion

        #region Constructor
        public RootDialog(IDialogFactory dialogFactory
            ) :
            base(LuisRootConstants.MODELID, LuisConstants.SUSBSCRIPTION)
        {
            SetField.NotNull(out _dialogFactory, nameof(dialogFactory), dialogFactory);
        }
        #endregion

        #region Luis Intents
        [LuisIntent(LuisConstants.NONE)]
        public async Task None(IDialogContext context, LuisResult result)
        {
            await Util.GenerateReplying(context);

            if (result.Query.ToLower().Contains(GeneralConstants.HUMAN_ACCESS))
            {
                await context.PostAsync("Disculpe los inconvenientes, en este momento no tenemos asesores disponibles para atención.");
                context.Call(new TicketDialog(_createTicketCommand), TicketDialogResumeAfter);
            }
            else
            {
                await context.PostAsync("Disculpa los inconvenientes, pero no puedo entenderte.");
                context.Wait(MessageReceived);
            }
        }
        #endregion

        #region Methods
        protected override async Task MessageReceived(IDialogContext context, IAwaitable<IMessageActivity> item)
        {
            var message = await item;
            Text = message.Text.ToLowerInvariant();
            await base.MessageReceived(context, item);
        }

        #endregion
    }

And here is the instrumentations inheritance.

   [Serializable]
    public class LuisRootDialog<R> : InstrumentedLuisDialog<object>
    {
        public LuisRootDialog(string luisModelId, string luisSubscriptionKey) : base(luisModelId, luisSubscriptionKey)
        {
        }
    }

I hope somebody can help me with this because i cant find the way to make work this without deleting the conversation.

itye-msft commented 6 years ago

Hi @eflorespalma , The exception states that there is something wrong with the IoC interface registration. In our sample we choose to use a static constructor to demonstrate the use. However, perhaps in your specific case, you may need to verify the correctness of registrations of the interfacess upon each new session or even new request, depeneds on you need and use case. The exception also says what you can do in your code to do it: check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency. So use your container to verify that each service is registered.

eflorespalma commented 6 years ago

I was using autofac 4.6 version so i have to downgrade to the version you use in the project instrumentation.