如何将DbContext(或任何其他对象)注入Dialogs?

时间:2016-04-03 12:56:15

标签: c# autofac botframework

我想在此示例PizzaOrderDialog.cs

中将订单保存到数据库

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

中使用它

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

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

MessageController.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);
    }
}

1 个答案:

答案 0 :(得分:0)

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

那是 - 你不应该做一些控制器类型的功能&amp;直接在您的演示文稿(视图)图层的代码中与db模型交互,名为PizzaOrderDialog.cs

你应该将db_context的单例引用注入到你的控制器中(你已经有了这部分)

AND

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

即使有说,根据用户在对话框中选择的内容提供5x4x10建议的地图 - 将所有内容传递给序列化(如您所述)并让您的服务器端视图逻辑在PizzaOrderDialog.cs中使用所有可能性视图模型比尝试公开模型层访问更好。

对于具体的排序提交,我将向控制器添加一个静态方法,您可以从对话框中调用该方法,再次封装db_context所需的任何交互以实现此目的。