简体   繁体   中英

Bot Framework - Luis Dialog - Set the LuisModel attribute from Web.config

I am writing a chat bot in Microsoft Bot Framework based on LUIS. (This is my first time using LUIS). I have a basic LuisDialog class where I would like to set the LuisModel attribute. The problem is, defining the LuisModel requires constant values. I would like to retrieve these values from the Web.config file.

This fails, and I get an error message saying "An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type". (It is because of retrieving the values from the Web.config file.)

Is there a way to retrieve these values from Web.config file and set them in the attribute?

I tried the following solution but it was not successful:

[Serializable]
[LuisModel(Constants.LuisModelId, Constants.LuisSubscriptionKey)]
public class LuisDialog : LuisDialog<object>
{
    //...
}

internal static class Constants
{
    internal const string LuisModelId = WebConfigurationManager.AppSettings.Get("LuisModelId");
    internal const string LuisSubscriptionKey = WebConfigurationManager.AppSettings.Get("LuisSubscriptionKey");
}

You can't set them directly on the attributes from the web.config since attributes are evaluated at compile time.

However, you CAN do it. The LuisDialog class constructor takes a parameter of ILuisService.

public LuisDialog(params ILuisService[] services)

Now, ILuisService, has a default implementation named appropriately, LuisService which has a constructor that takes an ILuisModel paramter

public LuisService(ILuisModel model)

Bear with me, I'm getting to the good stuff. ILuisModel's is implemented in the class LuisModelAttribute.

public class LuisModelAttribute : Attribute, ILuisModel, ILuisOptions, IEquatable<ILuisModel>

It's in LuisModelAttributes constructor that you should start to see where this is going

public LuisModelAttribute(string modelID, string subscriptionKey,
        LuisApiVersion apiVersion = LuisApiVersion.V2, string domain = null, double threshold = 0.0d)

This constructor takes a modelId and subscriptionKey! This is just what you're looking for. Now, the next question is how do you put all of this together? The answer is dependency injection using autofac.

I typically declare a new Autofac model class for all my DI registrations.

internal sealed class MainModule : Module

The first thing we need to register is an instance of the LuisModelAttribute

var luisModelAttr = new LuisModelAttribute(ConfigurationManager.AppSettings["luis:AppId"],
    ConfigurationManager.AppSettings["luis:ServiceKey"],
    LuisApiVersion.V2,
    ConfigurationManager.AppSettings["luis:APIHostName"])
{
    BingSpellCheckSubscriptionKey = ConfigurationManager.AppSettings["luis:BingSpellCheckKey"],
    SpellCheck = true
}

This didn't register anything, it just created an instance of the LuisModelAttribute class. NOW, register it.

builder.Register(c => luisModelAttr).AsSelf().AsImplmentedInterface().SingleInstance();

Next, register your Luis dialog, you will need to include ILuisService in the constructor paramters

builder.Register(c => new MyLuisDialog(c.Resolve<ILuisService>())
    .As<IDialog<IMessageActivity>>()
    .InstancePerDependency();

One last registration for the LuisService, or in our case ILuisService

builder.RegisterType<LuisService>()
    .Keyed<ILuisService>(FiberModule.Key_DoNotSerilialize)
    .AsImplementedInterface()
    .SingleInstance();

So, what happened here? Because LuisModelAttribute implements ILuisModel, Autofac will know to include our LuisModelAttribute as the parameter for LuisService, and will know to include the LuisService, which implements ILuisService, into our luis dialog, MyLuisDialog.

You specific implementation may vary but this example will get you what you need. Good luck!

Create a custom LuisModelAttribute

  public sealed class CustomLuisAttribute : LuisModelAttribute
    {
        public CustomLuisAttribute(string modelID, string subscriptionKey, LuisApiVersion apiVersion = LuisApiVersion.V2, string domain = null, double threshold = 0) 
            : base(modelID : ConfigurationManager.AppSettings["ModelId"], subscriptionKey : ConfigurationManager.AppSettings["LuisSubscriptionKey"])
        {
        }
    }

Use it as an attribute to your root dialog

[CustomLuisAttribute]
[Serializable]
public class RootDialog : LuisDialog<object>
{
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM