Bot Framework - Luis Dialog - 从 Web.config 设置 LuisModel 属性

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

我正在基于 LUIS 在 Microsoft Bot Framework 中编写聊天机器人。 (这是我第一次使用 LUIS)。我有一个基本的 LuisDialog class,我想在其中设置 LuisModel 属性。 问题是,定义 LuisModel 需要常量值。我想从 Web.config 文件中检索这些值。

这失败了,我收到一条错误消息说 "An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type"。 (这是因为从 Web.config 文件中检索值。)

有没有办法从 Web.config 文件中检索这些值并在属性中设置它们?

我尝试了以下解决方案,但没有成功:

[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");
}

您不能直接在 web.config 的属性上设置它们,因为属性是在编译时评估的。

但是,你可以做到。 LuisDialog class 构造函数接受 ILuisService 的参数。

public LuisDialog(params ILuisService[] services)

现在,ILuisService 有一个名为 LuisService 的默认实现,它有一个采用 ILuisModel 参数的构造函数

public LuisService(ILuisModel model)

请耐心等待,我要讲好东西了。 ILuisModel 是在 class LuisModelAttribute 中实现的。

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

在 LuisModelAttributes 构造函数中,您应该开始了解它的去向

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

此构造函数采用 modelId 和 subscriptionKey!这正是您要找的。 现在,下一个问题是如何将所有这些放在一起?答案是使用 autofac 进行依赖注入。

我通常会为我的所有 DI 注册声明一个新的 Autofac 模型 class。

internal sealed class MainModule : Module

我们需要注册的第一件事是 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
}

这没有注册任何东西,它只是创建了 LuisModelAttribute class 的一个实例。现在,注册它。

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

接下来,注册你的 Luis 对话框,你需要在构造函数参数中包含 ILuisService

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

LuisService 的最后一次注册,或者在我们的例子中是 ILuisService

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

所以,这里发生了什么?因为 LuisModelAttribute 实现了 ILuisModel,Autofac 将知道将我们的 LuisModelAttribute 作为 LuisService 的参数包含在内,并且将知道将实现 ILuisService 的 LuisService 包含到我们的 luis 对话框 MyLuisDialog 中。

您的具体实现可能会有所不同,但此示例将为您提供所需的内容。祝你好运!

创建自定义 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"])
        {
        }
    }

将其用作根对话框的属性

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