3

假设我想在此示例PizzaOrderDialog.cs 中将订单保存到数据库

我可以将 DbConext 注入控制器,例如这个https://github.com/Microsoft/BotBuilder/blob/master/CSharp/Samples/PizzaBot/Controllers/MessagesController.cs但如何在PizzaOrderDialog.cs中使用它

我不能只将 DbContext 作为构造函数参数传递给 PizzaOrderDialog 类,因为 PizzaOrderDialog 对象将被序列化然后反序列化。

最好的方法是什么?提前致谢!


消息控制器.cs

[BotAuthentication]
public class MessagesController : ApiController
{
    private static IForm<PizzaOrder> BuildForm()
    {
        var builder = new FormBuilder<PizzaOrder>();

        ConditionalDelegate<PizzaOrder> isBYO = (pizza) => pizza.Kind == PizzaOptions.BYOPizza;
        ConditionalDelegate<PizzaOrder> isSignature = (pizza) => pizza.Kind == PizzaOptions.SignaturePizza;
        ConditionalDelegate<PizzaOrder> isGourmet = (pizza) => pizza.Kind == PizzaOptions.GourmetDelitePizza;
        ConditionalDelegate<PizzaOrder> isStuffed = (pizza) => pizza.Kind == PizzaOptions.StuffedPizza;

        return builder
            // .Field(nameof(PizzaOrder.Choice))
            .Field(nameof(PizzaOrder.Size))
            .Field(nameof(PizzaOrder.Kind))
            .Field("BYO.Crust", isBYO)
            .Field("BYO.Sauce", isBYO)
            .Field("BYO.Toppings", isBYO)
            .Field(nameof(PizzaOrder.GourmetDelite), isGourmet)
            .Field(nameof(PizzaOrder.Signature), isSignature)
            .Field(nameof(PizzaOrder.Stuffed), isStuffed)
            .AddRemainingFields()
            .Confirm("Would you like a {Size}, {BYO.Crust} crust, {BYO.Sauce}, {BYO.Toppings} pizza?", isBYO)
            .Confirm("Would you like a {Size}, {&Signature} {Signature} pizza?", isSignature, dependencies: new string[] { "Size", "Kind", "Signature" })
            .Confirm("Would you like a {Size}, {&GourmetDelite} {GourmetDelite} pizza?", isGourmet)
            .Confirm("Would you like a {Size}, {&Stuffed} {Stuffed} pizza?", isStuffed)
            .Build()
            ;
    }

    internal static IDialog MakeRoot()
    {
        return new PizzaOrderDialog(BuildForm);
    }

    public async Task<Message> Post([FromBody]Message message)
    {
        return await Conversation.SendAsync(message, MakeRoot);
    }
}

PizzaOrderDialog.cs

[LuisModel("4311ccf1-5ed1-44fe-9f10-a6adbad05c14", "6d0966209c6e4f6b835ce34492f3e6d9")]
[Serializable]
public class PizzaOrderDialog : LuisDialog
{
    private readonly BuildForm<PizzaOrder> MakePizzaForm;

    internal PizzaOrderDialog(BuildForm<PizzaOrder> makePizzaForm)
    {
        this.MakePizzaForm = makePizzaForm;
    }

    [LuisIntent("")]
    public async Task None(IDialogContext context, LuisResult result)
    {
        await context.PostAsync("I'm sorry. I didn't understand you.");
        context.Wait(MessageReceived);
    }

    [LuisIntent("OrderPizza")]
    [LuisIntent("UseCoupon")]
    public async Task ProcessPizzaForm(IDialogContext context, LuisResult result)
    {
        var entities = new List<EntityRecommendation>(result.Entities);
        if (!entities.Any((entity) => entity.Type == "Kind"))
        {
            // Infer kind
            foreach (var entity in result.Entities)
            {
                string kind = null;
                switch (entity.Type)
                {
                    case "Signature": kind = "Signature"; break;
                    case "GourmetDelite": kind = "Gourmet delite"; break;
                    case "Stuffed": kind = "stuffed"; break;
                    default:
                        if (entity.Type.StartsWith("BYO")) kind = "byo";
                        break;
                }
                if (kind != null)
                {
                    entities.Add(new EntityRecommendation("Kind") { Entity = kind });
                    break;
                }
            }
        }

        var pizzaForm = new FormDialog<PizzaOrder>(new PizzaOrder(), this.MakePizzaForm, FormOptions.PromptInStart, entities);
        context.Call<PizzaOrder>(pizzaForm, PizzaFormComplete);
    }

    private async Task PizzaFormComplete(IDialogContext context, IAwaitable<PizzaOrder> result)
    {
        PizzaOrder order = null;
        try
        {
            order = await result;
        }
        catch (OperationCanceledException)
        {
            await context.PostAsync("You canceled the form!");
            return;
        }

        if (order != null)
        {
            await context.PostAsync("Your Pizza Order: " + order.ToString());
        }
        else
        {
            await context.PostAsync("Form returned empty response!");
        }

        context.Wait(MessageReceived);
    }

    enum Days { Saturday, Sunday, Monday, Tuesday, Wednesday, Thursday, Friday };

    [LuisIntent("StoreHours")]
    public async Task ProcessStoreHours(IDialogContext context, LuisResult result)
    {
        var days = (IEnumerable<Days>)Enum.GetValues(typeof(Days));

        PromptDialog.Choice(context, StoreHoursResult, days, "Which day of the week?");
    }

    private async Task StoreHoursResult(IDialogContext context, IAwaitable<Days> day)
    {
        var hours = string.Empty;
        switch (await day)
        {
            case Days.Saturday:
            case Days.Sunday:
                hours = "5pm to 11pm";
                break;
            default:
                hours = "11am to 10pm";
                break;
        }

        var text = $"Store hours are {hours}";
        await context.PostAsync(text);

        context.Wait(MessageReceived);
    }
}
4

1 回答 1

0

您要求做的事情违反了 MVC 范式。

也就是说 - 您不应该直接在演示(视图)层(也称为 PizzaOrderDialog.cs)的代码中执行一些控制器类型的功能并与数据库模型交互

您应该将一个对您的 db_context 的单例引用注入到您的控制器中(您已经拥有了那部分)

在控制器中添加函数以封装对话框的这些 db_context 交互,然后像现在使用BuildForm<PizzaOrder> makePizzaFormDialog 构造函数一样将这些函数的结果注入。

即使有人说,基于用户在对话框中选择的内容的 5x4x10 建议地图 - 以序列化方式传递整个内容(如您所提到的)并让 PizzaOrderDialog.cs 中的服务器端视图逻辑与所有可能性视图一起工作模型比尝试公开模型层访问要好。

特别是对于订购提交,我将向控制器添加一个静态方法,您可以从对话框中调用该方法,该方法再次封装了实现该操作所需的任何与 db_context 的交互。

于 2016-04-03T13:29:58.093 回答