Recently, I have been working on a release management strategy for bots built with the Bot Framework, using the tools we have in house at Mando where I work as a Technical Strategist. As part of this work I have setup various environments as part of the development lifecycle for our solutions. i.e. local development, CI, QA, UAT, Production etc. One of the issues I hit pretty quickly was the need to point the bot within each environment to it’s own LUIS model (if yo are not familiar with LUIS then check out my intro post here), as by default you decorate your LuisDialog with a LuisModel attribute as shown below, which means you need to hardcode your subscription key and model ID.
Obviously this need to hardcode isn’t ideal and I really needed to be able to store my Luis key and ID in my web.config so I could then transform the config file for each environment.
Thankfully this is pretty easy to achieve in Bot Framework using the in built dependency injection. Below are the steps I took to do this and at the end I will summarise what is happening.
- Add keys to your web.config for your Luis subscription key and model Id.
1234567<appSettings><add key="BotId" value="MandoMomaBot" /><add key="MicrosoftAppId" value="" /><add key="MicrosoftAppPassword" value="" /><strong><add key="luis:ModelId" value="<YOUR MODEL ID HERE>" /><add key="luis:SubscriptionId" value="<YOUR SUBSCRIPTION ID HERE>" /></strong></appSettings> - Amend your dialog that inherits from LuisDialog to accept a parameter of type ILuisService. This can then be passed into the base LuisDialog class. ILuisService itself uses a class, LuisModelAttribute which will contain our key and Id, more on that in a minute.
1234[Serializable]public class RootDialog : LuisDialog<IMessageActivity>{public <strong>RootDialog(ILuisService luis) : base(luis)</strong> { } - Next we create an AutoFac module, within which we register 3 types. Our Luis dialog, the ILuisService and the LuisModelAttribute. When we register the LuisModelAttribute we retrieve our key and Id from our web.config.
12345678910111213141516internal sealed class MainModule : Module{protected override void Load(ContainerBuilder builder){base.Load(builder);builder.Register(c => new LuisModelAttribute(ConfigurationManager.AppSettings["luis:ModelId"],ConfigurationManager.AppSettings["luis:SubscriptionId"])).AsSelf().AsImplementedInterfaces().SingleInstance();// Top Level Dialogbuilder.RegisterType<RootDialog>().As<IDialog<IMessageActivity>>().InstancePerDependency();// Singlton servicesbuilder.RegisterType<LuisService>().Keyed<ILuisService>(FiberModule.Key_DoNotSerialize).AsImplementedInterfaces().SingleInstance();}} - Then, in Global.asax.cs we register our new module.
123456789101112131415public class WebApiApplication : HttpApplication{protected void Application_Start(){RegisterBotModules();GlobalConfiguration.Configure(WebApiConfig.Register);}private void RegisterBotModules(){var builder = new ContainerBuilder();builder.RegisterModule<MainModule>();builder.Update(Conversation.Container);}} - Finally, in MessagesController, this is how you can create your Luis Dialog.
12345678910111213141516public async Task<HttpResponseMessage> Post([FromBody]Activity activity, CancellationToken token){if (activity.Type == ActivityTypes.Message){using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity)){await Conversation.SendAsync(activity, () => <strong>scope.Resolve<IDialog<IMessageActivity>>()</strong>);}}else{await HandleSystemMessage(activity);}var response = Request.CreateResponse(HttpStatusCode.OK);return response;}
That’s it. After those few steps you are good to go.
So, let’s summarise what is happening here. When you application loads the ILuisService and your Luis dialog are registered with AutoFac. Also registered is a LuisModelAttribute, into which we have passed our key and id from our web.config. Once that module has been registered, we can then get the instance of our dialog using scope.Resolve<IDialog<IMessageActivity>>(). This dialog takes an ILuisService as a parameter, but because we have registered that with AutoFac as well this passed in for us automatically. Finally the ILuisService needs a LuisModelAttribute, which, again, because we have registered this in our module is handled for us.
Once you have completed the above you can alter your Luis subscription key and model id by simply amending your web.config.